[ 4. C언어의 기본 - 연산자 ]
이번 포스팅은 연산자를 알아보도록 하겠습니다.
1) 연산자의 종류
분류 | 연산자 |
대입 연산자 | = |
산술 연산자 | +, -, *, /, % |
복합 대입 연산자 | +=, -=, *=, /=, %= |
증감 연산자 | ++, -- |
관계 연산자 | >, <, ==, !=, >=, <= |
논리 연산자 | &&, | |, ! |
조건 연산자 | ?: |
비트 논리 연산자 | &, |, ^, ~ |
비트 이동 연산자 | >>, << |
1) 대입 연산자
#include <stdio.h>
int main(){
int A = 10, B = 20;
A = B;
printf("%d\n", A);
}
|
cs |
A = B, B의 값을 A에 저장한다. 결괏값:20
1-1) 복합 대입 연산자 : 선 산술 후 대입 A += 5, A에 5를 먼저 더하고 후에 값을 다시 대입
#include <stdio.h>
int main(){
int A = 13, B = 20, C = 30, D = 40, E = 9, F= 7;
A += B;
printf("A += B는 %d 이다.\n", A);
A -= C;
printf("A -= C는 %d 이다.\n", A);
C *= D;
printf("C *= D는 %d 이다.\n", C);
C /= D;
printf("D /= C는 %d 이다.\n", C);
E %= F;
printf("E %%= F는 %d 이다.\n", E);
}
|
cs |
▶ A += B
- A와 B를 더한 값을 A에 저장한다. 결괏값 = 33
▶ A -= C
- A와 C를 뺀 값을 A에 저장한다. 결괏값 = 3 ( 33 - 30 )
▶ C *= D
- C와 D를 곱한 값을 C에 저장한다. 결괏값 = 1200 ( 30 * 40 )
▶ C /= D
- C를 D로 나눈 값을 C에 저장한다. 결괏값 = 30 ( 1200 / 40 )
▶ E %= F
- E를 F로 나누고, 나머지 값을 E에 저장한다. 결괏값 = 2 ( 9 % 7 )
2) 증감 연산자 : 선 연산 후 증감, 선 증감 후 연산으로 나뉜다.
증감 연산자의 종류에는 증가 연산자(++)와 감소 연산자( -- )의 두 가지 형태가 있는데,
연산자가 변수의 앞에 있는가 뒤에 있는가에 따라 전위형(Prefix)과 후위형(Postfix)으로 나눠어진다.
전위형은 ++a, --a 의 형태이고, 후위형은 a++. a-- 의 형태인데, 이들의 연산 결과는 다르기 때문에
주의하여 사용하여야 한다.
먼저 코드를 살펴보자.
#include <stdio.h>
int main(){
int a = 10,b = 10;
b = ++a;
printf(" a = %d, b = %d\n", a, b);
b = --a;
printf(" a = %d, b = %d\n", a, b);
b = a++;
printf(" a = %d, b = %d\n", a, b);
b = a--;
printf(" a = %d, b = %d\n", a, b);
}
|
cs |
연산식 | 실행 절차 | 실행 결과 |
b = ++a b = --a b = a++ b = a-- |
a에서 1을 더한 후 그 값을 b에 대입한다. a에서 1을 뺀 후 그 값을 b에 대입한다. a를 b에 대입한 후 a에 1을 더한다. a를 b에 대입한 후 a에 1을 뺀다. |
a = 11, b = 11 a = 9, b = 9 a = 11, b = 10 a = 9, b = 10 |
※ 위 코드로 실행하면 위의 표와 결괏값이 다를 수 있습니다.
- 위에서 대입한 값들을 호출하므로 값이 다를 수 있습니다. (표는 한줄씩 실행한 결과라고 생각하면 됨)
3) 관계 연산자 : 두 수의 관계를 비교하여 참(True) 또는 거짓(False)의 결과를 얻는다.
거짓은 0, 참은 1로 사용되지만 0외의 모든 숫자도 참으로 간주한다.
연산자 | 형식 | 의미 |
< | 식1 < 식2 | 식1 이 식2보다 작다. |
<= | 식1 <= 식2 | 식1 이 식2보다 작거나 같다. |
> | 식1 > 식2 | 식1 이 식2보다 크다. |
>= | 식1 >= 식2 | 식1 이 식2보다 크거나 같다. |
== | 식1 == 식2 | 식1 이 식2와 같다 |
!= | 식1 != 식2 | 식1 이 식2와 같지 않다. |
모든 관계 연산자는 같은 우선 순위를 가지며, 왼쪽에서 오른쪽으로 연산이 이루어진다.
따라서 관계 연산자는 프로그램이 수행되는 도중에 데이터나 계산 결과 등이 어떤 조건에 맞는지
판단하여 그 결과에 따라 실행할 명령문을 선택하는 데 이용된다.
#include <stdio.h>
int main(){
int a = 10, b = 20, c = 30, result;
result = a > b; // 0
printf(" 결괏값은 %d 이다.\n", result);
result = 19 <= b; // 1
printf(" 결괏값은 %d 이다.\n", result);
result = a == 10; // 1
printf(" 결괏값은 %d 이다.\n", result);
result = a + b == c; // 1
printf(" 결괏값은 %d 이다.\n", result);
result = b!= a; // 1
printf(" 결괏값은 %d 이다.\n", result);
★ result = c < b < a; // 1
printf(" 결괏값은 %d 이다.\n", result);
★ result = c > b > a; // 0
printf(" 결괏값은 %d 이다.\n", result);
}
|
cs |
4) 논리 연산자 : 두 개의 논리 값을 연산하여 (True) 또는 거짓(False)의 결과를 얻는다.
여러 개의 조건을 동시에 결합하여 판정하는 연산자로 OR, AND, NOT의 논리 연산을 수행한다.
관계 연산자와 마찬가지로 참(True)일 때에는 "1", 거짓 (False)일 때에는 "0"으로 표시한다.
예 |
(조건A) || (조건B) // 조건 A와 조건 B 중 둘 중 하나가 참이면 1 (조건A) && (조건B) // 조건 A와 조건 B 중 둘 다 참이면 1 , 하나라도 거짓이면 0 (조건A) ! (조건B) // 조건 B가 참이면 A는 0, B가 거짓이면 A는 1 |
#include <stdio.h>
int main(){
int A = 10, B = 20, C = 30, result;
result = ( A > B) || ( C > B);
printf("결괏값은 %d 이다.\n", result); // 결괏값 1
result = ( A > B ) && ( C > B);
printf("결괏값은 %d 이다.\n", result); // 결괏값 0
result = ! (A > B);
printf("결괏값은 %d 이다.\n", result); // 결괏값 1
}
|
cs |
5) 비트 연산자 : 컴퓨터에 숫자가 저장되는 최소 단위인 비트(0,1)별로 연산하여 결과를 얻는다.
연산자 | 설명 |
| | 비트 OR |
& | 비트 AND |
^ | 비트 XOR (Exclusive OR) |
~ | 비트 NOT |
<< | 비트를 왼쪽으로 시프트 |
>> | 비트를 오른쪽으로 시프트 |
&= | 비트 AND 연산 후 할당 |
|= | 비트 OR 연산 후 할당 |
^= | 비트 XOR 연산 후 할당 |
<<= | 비트를 왼쪽으로 시프트한 후 할당 |
>>= | 비트를 오른쪽으로 시프트한 후 할당 |
지금까지 자료형을 바이트 단위로 구분하여 사용했는데,
비트 연산자는 바이트 단위보다 더 작은 비트 단위로 연산하는 연산자이다.
- 비트(Bit) : 2진수를 저장하는 단위, 컴퓨터에서 사용할 수 있는 최소 단위이며 0과 1을 나타낸다.
- 바이트(Byte) : 8비트 크기의 단위이다.
비트 연산자는 비트로 옵션을 설정할 때 주로 사용하며 저장 공간을 아낄 수 있는 장점이 있다.
특이 이런 방식을 플래그(Flag)라고 부른다.
(참고) ※ 플래그란?
플래그(Flag)는 깃발에서 유래한 용어이다.
보통 깃발을 위로 들어올리면 ON, 아래로 내리면 OFF를 뜻한다.
이걸 정수의 비트에 활용하여 비트가 1이면 ON, 0이면 OFF를 나타낸다.
int와 같은 4바이트의 크기의 자료형은 몇 가지의 상태를 저장할 수 있을까?
4바이트는 32비트이므로 32개의 상태를 저장할 수 있다.
왜 플래그를 사용할까?
그냥 int형 변수를 선언해서 각각 상태를 저장하면 될텐데 굳이 플래그를 사용하는 이유는 뭘까?
플래그는 적은 공간에 정보를 저장해야 하고, 빠른 속도가 필요할 때 사용한다.
가장 대표적인 장치가 CPU인데, CPU는 내부 저장 공간이 매우 적기 때문에 각종 상태를 비트로 저장한다.
#include <stdio.h>
int main(){
int A = 10, B = 20, result;
result = A | B;
printf("결괏값은 %d 이다.\n", result); // 결괏값 30
result = A & B;
printf("결괏값은 %d 이다.\n", result); // 결괏값 0
result = A ^ B;
printf("결괏값은 %d 이다.\n", result); // 결괏값 30
result = ~A;
printf("결괏값은 %d 이다.\n", result); // 결괏값 -11
result = ~B;
printf("결괏값은 %d 이다.\n", result);
}
|
cs |
1) OR 연산자
- 두 개의 비트 중 하나라도 1이면 1을 반환하는 연산
위에 OR 결괏값을 보면 30이다. 왜 30으로 나올까?
A : 00000000 00000000 00000000 00001010
B : 00000000 00000000 00000000 00010100
답 : 00000000 00000000 00000000 00011110 = 30
A의 비트와 B의 비트 중 하나라도 1이면, 1을 반환한다.
2) AND 연산자
- A의 비트와 B의 비트가 모두 1이여야만 1을 반환한다.
OR연산자의 비트값을 보면 서로 일치하는 값이 하나도 없는게 눈에 보인다. 그러므로 답은 0
3) XOR 연산자 ( ^ )
- ^ 연산은 두 개의 비트가 서로 다른 경우에 1을 반환한다.
노린건 아닌데.. 두 개의 비트가 위에 보는것처럼 일치하는게 없다. 답은 OR과 동일하게 30이다.
4) NOT 연산자 ( 1의 보수)
- ~ 연산은 비트를 0에서 1로, 1에서 0으로 반전하는 연산이다. 보수연산이라고도 불린다.
A : 00000000 00000000 00000000 00001010 = (10)
답 : 1111111 1111111 1111111 11110101
첫 비트인 부호 비트가 1이기 때문에 음수이다. 그러므로 답은 -11이다.
B : 00000000 00000000 00000000 00010100 = (20)
답 : 1111111 1111111 1111111 11101011
첫 비트인 부호 비트가 1이기 때문에 음수이다. 그러므로 답은 -21이다.
다음은 시프트 연산에 대해 알아보자.
#include <stdio.h>
int main(){
int A = 10, result;
result = A << 1;
printf("결괏값은 %d 이다.\n", result); // 결괏값 20
result = A << 2;
printf("결괏값은 %d 이다.\n", result); // 결괏값 40
result = A << 3;
printf("결괏값은 %d 이다.\n", result); // 결괏값 80
result = A >> 1;
printf("결괏값은 %d 이다.\n", result);
result = A >> 2;
printf("결괏값은 %d 이다.\n", result);
result = A >> 3;
printf("결괏값은 %d 이다.\n", result);
}
|
cs |
1) << 연산자 (비트의 왼쪽 이동)
- A << B , A의 비트 열을 B칸씩 왼쪽으로 이동시킨 결과를 반환
- 왼쪽으로 밀려나는 비트들은(4바이트 초과) 그냥 버려진다.
A의 값을 10으로 대입 후 왼쪽으로 1칸 이동 시
0000 1010 (10) → 0001 0100 (20)
A의 값을 10으로 대입 후 왼쪽으로 2칸 이동 시
0000 1010 (10) → 0010 1000 (40)
A의 값을 10으로 대입 후 왼쪽으로 3칸 이동 시
0000 1010 (10) → 0101 0000 (80)
이 결과로 알 수 있는 사실은 비트의 열을 왼쪽으로 1칸씩 이동시킬 때마다 정수의 값은 두 배가 된다.
2) >> 연산자 (비트의 오른쪽 이동)
- A >> B, A의 비트 열을 B칸씩 오른쪽으로 이동시킨 결과를 반환
- 오른쪽으로 밀려나는 비트들은 그냥 버려진다.
A의 값을 10으로 대입 후 오른쪽으로 1칸 이동 시
0000 1010 (10) → 0000 0101 (5)
A의 값을 10으로 대입 후 오른쪽으로 2칸 이동 시
0000 1010 (10) → 0000 0010 (2)
A의 값을 10으로 대입 후 오른쪽으로 3칸 이동 시
0000 1010 (10) → 0000 0001 (1)
이 결과로 알 수 있는 사실은 비트의 열을 오른쪽으로 1칸씩 이동시킬 때마다 정수의 값은 2로 나누어진다.
여기까지 연산자 포스팅을 마무리합니다.