3-2. 그 외의 연산자
3-1에서 논리 연산자들을 알아봤다.
3-2에서는 그 외의 연산자들을 알아보겠다.
형 변환 연산자
형 변환 연산자는 피연산자가 1개이며 피연산자의 값을 원하는 형태로 바꾼다.
예를 들어 정수 -> 실수, 실수 -> 정수.
형 변환 연산자는 일시적으로 피연산자의 값을 원하는 형태로 바꾼다.
따라서 연산 후 메모리에 있는 피연산자의 형태나 값은 변하지 않는다.
int a = 10; 이라고 선언하면 a는 정수형이며 그 안의 값은 정수형이다.
이 값을 일시적으로 실수로 사용하고 싶으면 a 앞에 괄호로 (double)처럼 원하는 자료형을 넣으면 된다.
(자료형) 피연산자 처럼 말이다.
(double)10 -> 10.0 //double을 사용해 실수로 바꿈
(int)10.0 -> 10 //int를 사용해 정수로 바꿈
예제를 통해 자세히 알아보자.
#include <stdio.h>
int main(void)
{
int a = 20, b =3;
double res;
res = ((double)a) / ((double)b); //(double)을 사용해 a와 b의 값을 실수로 변환
printf("a = %d, b = %d\n", a, b);
printf("a / b의 결과 : %.1lf\n", res);
a = (int)res; //(int)를 사용해 res의 값에서 정수 부분만 추림
printf("(int) %.1lf의 결과 : %d\n", res, a);
return 0;
}
a를 b로 나누면 20/3이기에 정수의 나누기이기에 결과는 6이다. 그러나 double을 붙여 형 변환 연산을 구현해
6.7의 결괏값이 나왔다.
처음부터 a와 b를 double형으로 선언하면 편하겠지마, double형은 저장 공간이 크고 연산속도가 느리며
무엇보다 오차가 발생하므로 int형을 기본적으로 사용하는 것이 좋다.
자동 형 변환
컴퓨터는 데이터의 형태에 따라 다른 연산 방법을 사용하므로 피연산자가 2개 이상이라면 피연산자의 형태는 같아야 한다.
컴파일러는 컴파일 과정에서 피연산자의 형태가 다르다면 형태를 일치시키는 작업을 수행해야하는데, 이를 자동 형 변환 이라고 한다.
sizeof 연산자
sizeof 연산자는 피연산자를 하나만 사용할 수 있으며 피연산자의 크기를 바이트 단위로 계산해서 알려준다.
피연산자의 대상은 변수, 상수, 수식, 자료형 등이 된다.
sizeof(int) //int형의 크기를 구할 때
sizeof(10) //상수의 크기를 구할 때
예제를 통해 알아보자.
#include <stdio.h>
int main(void)
{
int a = 10;
double b = 3.4;
printf("자료형 변수의 크기 : %d\n", sizeof(a));
printf("double형 변수의 크기 : %d\n", sizeof(b));
printf("정수형 상수의 크기 : %d\n", sizeof(10));
printf("수식의 결괏값의 크기 : %d\n", sizeof(1.5 + 3.4));
printf("char 자료형의 크기 : %d\n", sizeof(char));
return 0;
}
결과를 보니 int형 변수는 4byte이다. 1byte는 8bit이므로 int형 변수는 메모리에 32bit의 데이터를 저장할 수 있다.
상수 10은 크기가 4byte지만, 4byte로 표현할 수 없는 범위의 상수를 사용하면 8byte가 되기도 한다.
sizeof연산자는 sizeof('A')처럼 문자열의 크기를 확인하는 데도 사용할 수 있다.
이때 문자열 끝에는 \0이 삽입되므로 값은 2가 된다.
sizeof 연산자와 괄호
sizeof는 연산자이므로 기본적으로 피연산자에 괄호를 사용할 필요가 없다.
printf("수식의 결괏값의 크기 : %d\n", sizeof 1.5 + 3.4);
그러나 이 경우 1.5만 두고 계산해서 8을 계산한 다음 3.4를 더해서 11.4가 된다.
printf("수식의 결괏값의 크기 : %d\n", sizeof char);
또한 이 경우도 char형 변수 선언문으로 인식되어 에러가 발생한다.
복합대입 연산자
복합대입 연산자는 연산 결과를 다시 피연산자에 저장한다.
산술 복합대입 연산자로는
+=, -=, *=, /=, %= 이렇게 5가지가 있다. 예제를 통해 연산 방법을 알아보자.
#include <stdio.h>
int main(void)
{
int a = 10, b = 20;
int res = 2;
a += 20; //a와 20을 더한 결과를 다시 a에 저장 (+=)
res *= b + 10; //b에 10을 더한 결괏값에 res를 곱하고 다시 res에 저장(*=)
printf("a = %d, b = %d\n", a, b);
printf("res = %d\n", res);
return 0;
}
복합대입 연산자는 대입 연산자의 특징을 그대로 가져간다.
1. 왼쪽 피연산자는 반드시 변수가 와야 한다.
2. 오른쪽 항의 계산이 모두 끝난 다음에 복합대입 연산자는 가장 마지막에 계산한다.
res *= b + 10; 의 계산 과정을 하나씩 살펴보자.
b + 10이 먼저 계산된다. b가 20이기에 b + 10은 30이다.
다음은 res * 30을 계산하는데 res = 2이기에 2 * 30은 60.
따라서 res = 60이라는 결괏값이 나온다.
콤마 연산자
,는 대입 연산자보다 우선순위가 낮아 여러 개의 수식을 차례로 나열해야 할 때에 사용한다.
조건 연산자
조건 연산자는 유일한 삼항 연산자로 ?와 : 기호를 함께 사용한다.
조건 연산자는 첫 번째 피연산자가 참이면 두 번째 피연산자가 결괏값이 되고
첫 번째 피연산자가 거짓이면 세 번째 피연산자가 결괏값이 된다.
첫 번째 피연산자에는 주로 조건식이 사용되며 사용 방벅은 다음과 같다.
(a > b) ? a : b //첫 번째 조건식이 참이면 a 선택, 조건식이 거짓이면 b 선택
예제로 자세히 알아보자.
#include <stdio.h>
int main(void)
{
int a = 10, b = 20, res;
res = (a > b) ? a : b; //a 와 b 중에 큰 값이 res에 저장
printf("큰 값 : %d\n", res);
return 0;
}
우선 (a > b)를 수행한다. a는 10이고 b는 20이므로 > 연산의 결과는 거짓을 뜻하는 0이 된다.
거짓이기 때문에 결괏값은 세 번째 피연산자인 b값, 즉 20이 된다.
비트 연산자
비트 연산자는 비트열로 알아보도록 하자.
비트별 논리곱 연산자
00000000 00000000 00000000 00001010 (a = 10)
00000000 00000000 00000000 00001100 (b = 12)
------------------------------------
00000000 00000000 00000000 00001000 (a & b = 8)
논리곱 연산은 &로 표현한다. &연산은 두 비트가 모두 1인 경우에만 1로 계산한다.
비트별 배타적 논리합 연산자
00000000 00000000 00000000 00001010 (a = 10)
00000000 00000000 00000000 00001100 (b = 12)
------------------------------------
00000000 00000000 00000000 00000110 (a ^ b = 6)
배타적 논리합은 ^로 표현하며 두 피연산자의 진리값이 서로 다를 때만 참이 된다.
즉, 둘 다 참이거나 둘 다 거짓이면 거짓이고, 하나는 참이고 다른 하나가 거짓인 경우에 참이 된다.
비트별 논리합 연산자
00000000 00000000 00000000 00001010 (a = 10)
00000000 00000000 00000000 00001100 (b = 12)
------------------------------------
00000000 00000000 00000000 00001110 (a | b = 14)
논리합은 |로 표현하며 두 비트 중에 하나라도 참이면 1로 계산한다.
비트별 부정 연산자
00000000 00000000 00000000 00001010 (a = 10)
------------------------------------
11111111 11111111 11111111 11110101 (~a = -11)
비트별 부정 연산자는 ~로 표현하며 피연산자가 하나이다. 피연산자의 비트를 반전시킨다.
비트 이동 연산자
a << 1은 a의 비트들을 모두 왼쪽으로 한 비트씩 이동시킨다. 이때 왼쪽으로 밀려나는 비트는 사라지고 오른쪽의 남는 비트는 0으로 채워진다.
a >> 1은 반대이다.
연산자 우선순위는 3-1에서 올렸기에 또 올리지는 않는다.