Skip to content

Latest commit

 

History

History
219 lines (173 loc) · 13.1 KB

chapter03.md

File metadata and controls

219 lines (173 loc) · 13.1 KB

여러 가지 연산자

컴퓨터는 계산(compute)을 하는 기계입니다.
따라서 컴퓨터의 기본 작업은 어떤 수학적인 계산을 하는 데에 있습니다.

프로그램에서 계산을 할 땐 수식 expression 을 사용합니다.
수식은 연산자 operator피연산자 operand 로 이루어져 있으며 하나의 값을 갖죠.
가장 간단한 수식은 피연산자 하나로 이루어져 있으며 그 값은 피연산자 자신입니다.
예를 들어 78 이라는 숫자 자체로 수식이며 그 값은 78입니다.
그리고 5 + 19 라는 수식의 값은 26이죠.

연산자는 수학적 연산을 하는 산술 연산자, 값을 비교하는 관계 연산자, 논리적인 판단을 하는 논리 연산자 등으로 구분할 수 있습니다.
혹은, 필요로 하는 피연산자의 개수에 따라 단항 연산자, 이항 연산자, 삼항 연산자로 구분할 수도 있습니다.

C언어는 다음과 같은 연산자들을 지원하는데, 이런 것들이 있구나 하고 훑고 넘어가면 됩니다.
포인터라던가 구조체라던가 하는 녀석들은 애초에 아직 배우지도 않았...ㅋ
그런 의미에서 포인터 연산자와 구조체 연산자는 각각 포인터와 구조체를 배울 때 다루도록 하겠습니다.
각각의 연산자에 대한 구체적인 설명은 아래에서 이어 가도록 하겠습니다.

분류 연산자 의미
대입 = 우항을 좌항에 대입
산술 +, -, *, /, % 사칙연산과 나머지 연산
부호 +, - 양수와 음수를 표시
증감 ++, -- 1 증가 또는 감소
관계 >, <, ==, !=, >=, <= 우항과 좌항 비교
논리 &&, ||, ! 논리적인 부울 연산
조건 ? : 조건에 따른 선택적 실행
콤마 , 피연산자들을 순차적으로 실행
비트 &, |, ^, ~, <<, >> 비트 단위 부울 연산 및 이동 연산
크기 sizeof 변수, 상수 또는 자료형의 byte 단위 크기
형변환 ( 자료형 ) 변수나 상수의 자료형 변환
포인터 *, &, [ ] 주소 계산 또는 주소가 가리키는 값 추출
구조체 ., -> 구조체 멤버 참조

산술 연산자

연산자 피연산자 개수 형식
+ 2 a + b 숫자 a 에 숫자 b 를 더한 값
- 2 a - b 숫자 a 에서 숫자 b 를 뺀 값
* 2 a * b 숫자 a 에 숫자 b 를 곱한 값
/ 2 a / b 숫자 a 를 숫자 b 로 나눈 값
% 2 a % b 숫자 a 를 숫자 b 로 나눈 나머지

사칙연산에 해당하는 연산자는 다들 익숙하실 겁니다.
나머지 연산자는 생소하신 분도 있을 수 있지만, 이해하는 데 어렵지 않을 것으로 생각합니다.
우리는 생각보다 나머지 연산을 일상적으로 사용하고 있거든요.
12h 시간은 24h의 시간의 % 12 나머지 연산 결과랍니다?ㅋ

부호 연산자

연산자 피연산자 개수 형식
+ 1 +a 숫자 a 의 부호를 그대로 유지한 값
- 1 -a 숫자 a 의 부호를 반대로 변경한 값

+ 연산자의 경우 그것을 사용하지 않았을 때와 값이 변하지 않으므로 거의 사용하지 않지만, 부호가 있는 수임을 명시적으로 나타내고자 할 때 사용할 수 있습니다.
- 연산자를 사용하면 양수를 음수로, 음수를 양수로 변환할 수 있죠.

증감 연산자

연산자 피연산자 개수 형식
++ 1 a++ 숫자 a 에 1 증가한 값 (수식이 포함된 줄 실행 후 수행)
++a 숫자 a 에 1 증가한 값 (수식이 포함된 줄 실행 전 수행)
-- 1 a-- 숫자 a 에 1 감소한 값 (수식이 포함된 줄 실행 후 수행)
--a 숫자 a 에 1 감소한 값 (수식이 포함된 줄 실행 전 수행)

증감 연산자가 피연산자의 앞에 붙든 뒤에 붙든, 피연산자에 대한 연산 자체는 차이가 없습니다.
다만, 연산을 수행하는 시점이 언제인지가 다르죠.
증감 연산자가 포함된 줄의 코드가 실행될 때, 증감 연산자가 피연산자 앞에 있다면 그 줄이 실행되기 전에 증감 연산이 먼저 수행되며, 피연산자 뒤에 있다면 그 줄이 실행된 후에 증감 연산이 수행됩니다.

한 줄에 동일한 피연산자에 대한 증감연산이 두 번 이상 수행될 경우 수행 순서에 대한 모호함이 있을 수 있어 이를 같은 줄에 작성하는 것은 권장되지 않습니다.
가끔 이런 걸로 퀴즈를 내는 교수가 있는데... 그건 교수가 너무한 거......ㅎ

관계 연산자

연산자 피연산자 개수 형식
> 2 a > b 숫자 a 가 숫자 b 보다 크면 1, 그렇지 않으면 0
< 2 a < b 숫자 a 가 숫자 b 보다 작으면 1, 그렇지 않으면 0
== 2 a == b 숫자 a 가 숫자 b 와 같다면 1, 그렇지 않다면 0
!= 2 a != b 숫자 a 가 숫자 b 와 다르다면 1, 그렇지 않다면 0
>= 2 a >= b 숫자 a 가 숫자 b 보다 크거나 같다면 1, 그렇지 않다면 0
<= 2 a <= b 숫자 a 가 숫자 b 보다 작거나 같다면 1, 그렇지 않다면 0

관계 연산자는 두 숫자의 대소관계를 나타냅니다.
수식이 나타내는 대소관계가 참이 될 경우 그 값은 1, 거짓이 될 경우 그 값은 0 이 되죠.
언어에 따라 true, false 등의 값으로 나타내는 경우도 있지만 C언어에서는 10 으로 나타냅니다. C언어에는 0은 거짓, 0이 아닌 숫자는 참으로 해석하는 약속이 존재하는데, 일반적으로 참을 나타낼 때는 다른 숫자보다는 1을 사용합니다.
문자형 자료의 경우 아무 문자도 없이 비어있음을 의미하는 \0 (null 이라고도 합니다)이 내부적으로는 숫자 0 을 의미하여, 이 값일 때 거짓, 다른 문자일 때는 `로 취급됩니다.

논리 연산자

연산자 피연산자 개수 형식
&& 2 a && b 수식 a 와 수식 b 가 모두 참이라면 1, 그렇지 않다면 0
|| 2 a || b 수식 a 와 수식 b 중 하나라도 참이면 1, 그렇지 않다면 0
! 1 !a 수식 a 가 참이라면 0, 거짓이라면 1

여기서 말하는 참과 거짓은 앞서 관계 연산자에서 언급된 숫자와 문자에서의 참과 거짓에 해당합니다.
논리 연산자의 피연산자에 해당하는 수식으로는 관계 연산자가 오는 경우가 많죠.

조건 연산자

연산자 피연산자 개수 형식
? : 3 a ? b : c 수식 a 가 참일 경우 b, 거짓일 경우 c

조건 연산자는 C언어에서의 유일한 삼항 연산자이기 때문에 '삼항 연산자'라는 이름으로 대변됩니다.
첫번째 피연산자가 참일 경우에는 두번째 피연산자의 값이 이 연산의 값이 되며, 거짓일 경우에는 세번째 피연산자의 값이 이 연산의 값이 됩니다.

이와 같이 조건에 따라 다른 값을 갖도록 하는 것은 다음 시간에 다룰 조건문을 통해서도 수행할 수 있지만 각각의 경우에 장단점이 있습니다.
이에 대해서는 조건문에 대해 다루며 다시 이야기하도록 하겠습니다.

콤마 연산자

연산자 피연산자 개수 형식
, 2 a, b 수식 a 를 수행한 후 수식 b 를 수행한 값

콤마 연산자를 사용하면 우선 앞에서부터 수식이 계산됩니다.
계산을 마친 후에는 가장 마지막 값이 이 수식의 최종 값이 되죠.
사실 잘 쓰이진 않습니다.
보통은 콤마 연산자를 사용할 수 있는 상황에서 세미콜론을 찍고 다음줄로 넘어가거든요.

비트 연산자

연산자 피연산자 개수 형식
& 2 a & b 비트 단위로 ab 가 모두 1 이면 1, 그렇지 않다면 0
| 2 a | b 비트 단위로 ab 중 하나라도 1 이면 1, 그렇지 않다면 0
^ 2 a ^ b 비트 단위로 ab 가 서로 다르면 1, 같으면 0
~ 1 ~a 비트 단위로 a0 이면 1, 1 이면 0
<< 2 a << b 비트 단위로 a 를 좌측으로 b 만큼 이동한 값
>> 2 a >> b 비트 단위로 a 를 우측으로 b 만큼 이동한 값

비트 연산자는 비트 단위로 연산을 수행합니다.
비트는 컴퓨터에서 사용하는 가장 작은 단위로, 0 또는 1의 값을 갖습니다.
이 녀석이 8개 모이면 바이트가 되고...하는 단위에 대한 이야기는 궁금하면 구글에게 물어보도록 하죠.
비트 연산자는 숫자를 있는 그대로 연산하지 않고 비트 단위로 연산합니다.

예를 들어 78과 59의 연산이라고 할 때, 이것을 이진수 0111100001011001 로서 각 자리수별로 연산을 수행합니다.
이 두 수 사이의 & 연산은 두 수 모두 1을 가진 자리만 1이 되어 01011000, | 연산은 하나라도 1인 자리는 1이 되어 01111001, 그리고 ^ 연산은 하나만 1인 자리만 1이 되어 00100001 이 됩니다.
78의 ~ 연산 결과는 10000111 이죠.
<<>> 는 시프트(shift) 연산이라고 부르는데, 비트를 한 칸씩 옆으로 밀어냅니다.
<< 의 경우 왼쪽으로 밀어내며 왼쪽으로 빠져나오는 값은 버리고 오른쪽은 0으로 채웁니다.
그리고 >> 의 경우 오른쪽으로 밀어내며 오른쪽으로 빠져나오는 값을 버리는데, 왼쪽을 무엇으로 채우는지는 부호 여부에 따라 달라집니다.
부호가 없는 수(unsigned)의 경우 0으로 채워지며, 부호가 있는 수(signed)의 경우 가장 왼쪽에 있던 비트와 동일한 값으로 채워지죠.

대입 연산자

연산자 피연산자 개수 형식
= 2 a = b 변수 ab 의 값을 대입 후 a 의 값
+= 2 a += b a = a + b 와 동일
-= 2 a -= b a = a - b 와 동일
*= 2 a *= b a = a * b 와 동일
/= 2 a /= b a = a / b 와 동일
%= 2 a %= b a = a % b 와 동일
&= 2 a &= b a = a & b 와 동일
|= 2 a |= b a = a | b 와 동일
^= 2 a ^= b a = a ^ b 와 동일
<<= 2 a <<= b a = a << b 와 동일
>>= 2 a >>= b a = a >> b 와 동일

가장 기본적인 형태의 대입 연산자는 = 이며 나머지는 이로부터 파생된 연산자입니다.
대입 연산도 값을 갖기 때문에 a = b = c 와 같은 연산이 가능합니다.
b = c 연산이 먼저 이루어지고 그 값이 담긴 ba 에 또 대입되는 형태죠.

크기 연산자

연산자 피연산자 개수 형식
sizeof 1 sizeof(a) a 의 크기

크기 연산자의 형태는 함수를 호출하는 것과 유사하지만 함수가 아니고 연산자입니다.
변수나 상수, 자료형에 대하여 그것이 몇 byte 공간을 차지하는지를 값으로 갖죠.
sizeof(char) 의 값은 1 이라던가, 이 연산자는 주로 메모리 동적할당을 할 때 사용됩니다.
그것에 대해 다룰 때 다시 살펴보도록 하죠.

형변환 연산자

연산자 피연산자 개수 형식
( ) 1 (Datatype) a 자료형이 Datatype으로 변환된 a 의 값

언뜻 보기엔 괄호 안과 밖, 두 개의 피연산자가 있는 것 같지만 괄호 다음에 오는 것만 피연산자입니다.
정확히는 (int) 는 주어진 자료를 int 형으로 변환하는 연산자, (char) 는 주어진 자료형을 char 형으로 변환하는 연산자, 이런 식으로 자료형마다 하나씩 연산자가 있다고 볼 수 있죠.
자료형이 서로 다른 자료들끼리의 연산을 할 때 기본적으로 더 큰 자료형으로 자동 형변환이 이루어지는데
(가령, intlong 의 연산에서는 intlong 으로 변환되어 계산되는 식)
반대로 더 작은 자료형으로 형변환을 하고자 한다면 형변환 연산자를 사용해야 합니다.

이 경우, 나타낼 수 있는 값의 범위가 줄어들어 기존에 갖고 있던 값의 일부가 누락될 수 있습니다.
예를 들어 float 형의 자료가 3.141592 를 갖고 있었는데 이를 int 형으로 형변환하면 소수점 아래의 값이 누락되고 3 만 남는 식이죠.
그리고 40000 이라는 값을 가진 int 자료를 -32768 ~ 32767 만 저장 가능한 short 형으로 변환할 경우, 오버플로우가 발생하여 -25536 이 됩니다.

형변환 연산을 할 땐 이러한 값의 범위를 유의해야 합니다.

과제

이번 차시는 과제가 없습니다!
그냥 이런 연산자들이 있구나 하는 걸 알아두시면 됩니다.
필수는 아니고 선택적으로 자유로운 연산자 실습을 수행하고, 그 결과를 PR 주시면 칭찬해드리겠습니다...?ㅋ