C나 C++을 하다 보면은 shift 연산을 할 때가 많이 있습니다.
shift연산은 로우레벨 연산으로 비트를 왼쪽이나 오른쪽으로  밀어 내는 연산입니다.

shift 연산은 산술적으로 빠른 제곱근이 계산 됩니다. 왼쪽 shift 는 2^n 계산이 되고, 오른쪽 shift는 1/2^n이 되죠.

여기서 이야기 할 내용은..  이 유용한 shift연산에 한가지 함정이 있다는 겁니다.
그것은 바로 32번 shift하는 것이지요. (32bit 운영체제 임을 가정 합니다.)

아래의 코드와 실행 결과를 확인 해 보겠습니다.

unsigned int x와 signed int y 두 개의 변수가 있는데.. 8번 shift하면은 x와 y의 값이 달라지게 됩니다. 이게 전형적인 shift 연산의 결과 입니다. ( 값이 다른 것은 굳이 설명 하지 않겠습니다. unsigned와 signed는 다른거 아시리라 가정 합니다.)

그다음에 밑에 보면은 32번 shift를 수행 합니다. 우리는 예상 하기로는.. x와 y를 왼쪽으로 32번 shift하면은 0이 나오길 기대 합니다. (y를 오른쪽으로 shift 하면 -1이 나오길 기대합니다.)

하지만 결과는 예상을 뛰어 넘습니다. 둘다 같은 값이 나오게 됩니다. 무슨 일일까요?

표준 C, C++ 규약인 ISO/IEC 14882:2003 5.8 섹션에서 다음과 같이 이야기 하고 있습니다.

5.8 Shift operators
1    The shift operators << and >> group left-to-right.
shift-expression: additive-expression
shift-expression << additive-expression shift-expression >> additive-expression
[expr.shift]

The operands shall be of integral or enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.

2    The value of E1 << E2 is E1 (interpreted as a bit pattern) left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 multiplied by the quantity 2 raised to the power E2, reduced modulo ULONG_MAX+1 if E1 has type unsigned long, UINT_MAX+1 otherwise. [Note: the constants ULONG_MAX and UINT_MAX are defined in the header <climits>). ]

3    The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity 2 raised to the power E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

오른쪽 operand가 음수 이거나 왼쪽 피연산자 데이터 타입의 비트 길이보다 크게 되면은 Undefined 로 정의 되어 있습니다.

제가 이걸 알게 된 경우는 비트 마스크를 사용 하다 알게 되었는데, 컴파일러는 표준대로  undefined로 처리를 해버려 버그를 유발 하게 됩니다.

저처럼 마스크 연산을 위해 32번 shift를 해야 하는 경우가 발생 하게 되면은, 아무 생각 없이 위와 같이 하면 안됩니다. 16번씩 두번 shift를 하던가 해야 됩니다.

다음 그림은 제가 원하는 결과를 수행 하기 위해 수정 한 코드 입니다.

결과를 보면 알 수 있듯이, x는 0이 나오고 y는 오른쪽 shift일땐 -1이 나오고 왼쪽 shift는 0이 나왔습니다.

shift연산은 굉장히 유용한 연산이고 자주 사용 되는 연산이나, 위와 같은 특수한 경우를 보통 모르고 있기 때문에 유의 하여야 됩니다.

+ Recent posts