' [C/C++] 5.2강 - 시프트 연산자가 작동하는 방법

Programming/C & C++

[C/C++] 5.2강 - 시프트 연산자가 작동하는 방법

mdisprgm 2021. 6. 12. 13:31
728x90
728x90

주제 : 비트 연산 중 시프트 연산

 

요구사항 : 시프트 연산의 기능에 대한 이해

 

(1) 버려지는 비트

 

위 코드에서 a는 char로 선언됐다.

 

char는 범위가 -128 ~ 127 까지라고 했는데

 

어떻게 1024가 출력된 것일까?

 

그 이유는

 

<< 연산자는 오른쪽으로 밀린 비트가 버려지지 않고 그대로 유지되기 때문이다.

 

그러니까 (4bits) a = 1; 일때 a << 3; 은

 

0 0 0 1 0 0 0

 

이런 형태가 된다는 것이다.

 

이러면 4bits가 7bits가 되었죠?

 

똑같이

 

8bits로 char형이었던 것이

 

10칸 이동하면서 더 큰 자료형이 된 것입니다.

 

이걸 %d로 출력을 하니 1024가 문제없이 출력이 됐죠.

 

 

반면 >> 연산자는 다릅니다.

 

왼쪽으로 밀린 것은 얄짤없이 버려집니다.

 

 

(2) 채워지는 비트

진법에 대한 이해가 충분하다면

 

이진법에서 자릿수가 하나씩 늘어나거나 줄어든다면

 

그것은 십진법으로 표현했을 때 2배, 1/2배 된다는 것을 알고 있을 것이다.

(십육진법도 마찬가지로 16배, 1/16배)

 

그리고 위에서도 확인했다시피 이것은 시프트 연산과 관련이 있다.

 

시프트 연산으로 << 1이나 >> 1을 해버리면

 

해당 정수의 값이 2배, 또는 1/2배가 된다.

 

(1) 예제에서 1 << 30 을 했더니 \(2^{30}\) 이 출력된 것처럼 말이다.

 

 

이 코드를 다시 실행해보자.

#include <stdio.h>

int main() {
	int a;
	
	a = 16;
	printf("%d\n", a >> 3);
}

 

이걸 그림으로 한번 그려보면

 

a = 16

0 0 0 1 0 0 0 0

 

 a >> 3

0 0 0 0 0 0 1 0

 

이렇게 a >> 3은 2가 나온다는 것을 볼 수 있다.

 

또한

 

보다시피 왼쪽으로 3칸 밀리고 빈 자리는 0으로 채워진다.

 

아! 시프트 연산으로 빈 공간이 생기면 그 비트는 0으로 채워지는 것이구나!

 

 

반은 맞고, 반은 틀리다.

 

왜냐하면 항상 0으로 채워지는 것이 아니기 때문인데

 

위 코드에서 a를 -16으로 바꾸고 실행해보자.

 

#include <stdio.h>

int main() {
	int a;
	
	a = -16;
	printf("%d\n", a >> 3);
}

 

수학적으로 생각했을 때 결과는 정상이다. \(-16\times\frac{1}{2^{3}}\) 이니 -2가 맞다.

 

그런데 꼼꼼히 생각해보면 어딘가 이상한 점이 있다.

 

 

이걸 한번 그림으로 그려보면

 

a = -16

1 1 1 1 0 0 0 0

 

a >> 3

0 0 0 1 1 1 1 0

 

-16 >> 3 을 했더니 빈 공간 3bits가 0으로 채워져 00011110이 되었다.

 

-16 >> 3을 한다면 반환값은 -2가 나와야하는데, 00011110은 최상위 비트가 0이므로

 

음수가 아니다.

 

실제로 변환해보아도 30이라는 엉뚱한 숫자가 나온다.

 

이것이 바로 밀려난 비트가 항상 0으로 채워질 때

 

생기는 문제이다.

 

음수는 부호가 유지되지 않는다는 문제..

 

그래서 C언어에서는 시프트 연산을 할 때

 

무조건 0으로 채워지는 것이 아니라

 

최상위 비트가 1이었다면, 즉 원래 정수가 음수라면

 

밀려나서 채워지는 비트도 1로 채워지게 된다.

 

즉, 11110000(2)은 3칸 밀렸을 때 빈 자리가 1로 채워져 11111110(2)이 되죠

 

-16 >> 3

1 1 1 1 1 1 1 0

 

이것을 변환해보면 -2가 잘 나오는 걸 볼 수 있다.

 

두 번째가 signed일 때 값이다.

 

그러면 0으로 채워지도록 시프트하는 것은 못하는 걸까?

 

유감스럽게도 C에서는 언어적 차원에서 지원하는 연산자는 없다.

 

그러나 Java 등 다른 일부 프로그래밍 언어에서는 이를 위해 또 다른 시프트 연산자가 존재한다고 한다.

 

만약 C에서 그러한 연산을 원한다면 `logical shift in c` 같은 검색어로 찾아보면 나올 것..

 

 

 

 

끝.

728x90
728x90
'