5-2-바.회전 연산

회전(Rotate) 연산은 쉬프트 연산과 유사한 비트 조작 명령이다. 쉬프트는 비트를 선형으로 이동시키는데 비해 회전 연산은 원형으로 이동시킨다. 비트 이동에 의해 밀려나는 비트는 버려지지 않고 반대쪽으로 다시 이동된다는 것이 특징이다. 회전 연산은 쉬프트 연산에 비해 많이 사용되지 않기 때문에 연산자 형태로는 제공되지 않으며 _rotl, _rotr 함수로 제공된다. C 수준에서는 사용할 일이 그리 많지 않다. 과거 도트 프린터나 잉크젯 프린터의 경우 헤더가 수직으로 배열되어 있으므로 한 비트씩 추출하여 한 줄을 만들었는데 이럴 때 회전 연산이 사용되었다. 기본 동작을 그림으로 그려 보면 다음과 같다.

쉬프트 연산과 개념적으로 크게 틀리지 않다. 다음 코드는 32비트의 정수를 왼쪽 방향으로 4비트 회전한 결과를 출력한다.

 

unsigned i=0x12345678;

printf("%x\n",_rotl(i,4));

 

16진수 0x12345678을 왼쪽으로 4비트 회전시키면 각 비트는 4비트 왼쪽으로 이동하며 제일 왼쪽의 4비트는 한바퀴를 돌아서 오른쪽에 나타난다. 출력 결과는 23456781이 될 것이다. 오른쪽으로 4비트 회전시키면 81234567이 될 것이고 당연한 얘기겠지만 어느 방향으로나 32비트 회전시키면 원래값이 될 것이다.

회전 연산과 쉬프트 연산을 함께 사용하면 비트를 아주 섬세하게 제어할 수 있다. 비트맵 이미지를 회전시킨다거나 변형할 때 각 점을 구성하는 비트들을 자유롭게 조작할 수 있다. 두 연산은 CPU가 기계 차원에서 직접 지원하는 저수준 연산이므로 속도가 아주 빠르다.

회전 연산의 특징은 원래 값으로 복구가 가능하다는 점이다. 왼쪽으로 한칸 돌렸다가 오른쪽으로 다시 한칸 돌리면 제자리다. 그래서 XOR 연산과 함께 암호화를 위해 자주 사용된다. 쉬프트나 &, | 연산은 원래값을 파괴시키지만 회전과 XOR은 원래값을 보존하면서 값을 변경시킨다. 그래서 돌리고 반전시켜 놓는 방법으로 간단한 암호화에 응용되기도 한다. 최초 회전한 반대 방향으로 다시 회전시키면 원래값을 구할 수 있으며 그래서 원래 값을 복구할 수 있어야 하는 암호화에 적합하다.

다음 예제는 지금까지 배운 여러 가지 연산자를 골고루 사용하여 10진수를 16진수로 바꿔 출력한다. 물론 printf의 %X 서식을 사용하면 훨씬 더 간단하게 16진 출력을 할 수 있지만 연산자 연습을 위해 printf의 도움없이 직접 16진수로 바꿔 보는 것이다. 입력받은 정수를 16진수 형태로 출력하는데 상하위 니블(4비트)에 대해 대응되는 문자를 찾아 출력해야 한다.

 

: Dec2Hex

#include <Turboc.h>

 

void main()

{

     int input;

     int low,hi;

 

     for (;;) {

          printf("0~255사이의 수를 입력하시오(끝낼 때 -1) : ");

          scanf("%d",&input);

          if (input == -1) {

              break;

          }

 

          hi=input >> 4;

          low=input & 0xf;

          printf("입력한 수의 16진 표기 = %c%c\n",

              hi+'0'+(hi>9)*7,low+'0'+(low>9)*7);

     }

}

 

실행 결과는 다음과 같다. 입력한 10진수를 16진 표기법으로 바꿔 출력해 준다.

 

0~255사이의 수를 입력하시오(끝낼 때 -1) : 129

입력한 수의 16진 표기 = 81

0~255사이의 수를 입력하시오(끝낼 때 -1) : 200

입력한 수의 16진 표기 = C8

 

0~255사이의 10진수는 8비트 크기를 가지며 상하위 4비트가 16진수 한 자리가 되어 두 자리의 16진수로 표기할 수 있다. 상하위 니블을 hi, low 변수에 분리하기 위해 >> 연산자와 & 연산자를 사용했다. 상위에 있는 4비트값을 추출하려면 >> 연산자로 4회 쉬프트하면 되고 하위 4비트만을 남기려면 & 연산자로 상위 4비트를 마스크 오프시키면 된다.

이렇게 구한 각 자리값을 16진 문자로 바꾸려면 일단 '0'을 더하고 9보다 더 큰 값일 경우 7을 더한다. 이 식에 대해서는 앞서 이미 설명한 바가 있는데 관계 연산문이 참일 때 1을 리턴한다는 점을 이용하여 한 문장으로 대응되는 문자를 구할 수 있다.