[2003년 기말 3번] 비트/논리 연산자 (MASK)
1. 목적
- 비트(Bit) 단위 연산과 마스크(MASK) 개념 이해
- 임의의 숫자 생성 및 처리
2. 문제
임의 숫자를 생성하여 17 ~ 24 째 비트만 받아서 출력하라. 단 하나의 32비트 크기의 정수(최대값은 2 ^ 32 - 1 = 4294967295) 를 만들어 쓰되 rand() 함수를 사용하여 구현(16비트 값 출력) 하라.
출력 결과는 아래와 같다.
임의의 정수 : 00101000 11110110 00001110 11101111 687214319
추출된 정수 : 40 246 14 239 687214319
압축된 정수 : 00000000 00000000 00000000 11110110 246
임의의 정수 : 00101000 11110110 00001110 11101111 687214319
추출된 정수 : 40 246 14 239 687214319
압축된 정수 : 00000000 00000000 00000000 11110110 246
임의의 정수 : 00100110 00100110 10000001 00001111 640057615
추출된 정수 : 38 38 129 15 640057615
압축된 정수 : 00000000 00000000 00000000 00100110 38
... (엔터를 치면 계속 반복)
- 마스크는 덮었을때 그 값만 나오게 만드는 필터를 의미 (17 ~ 24번째 비트가 '1' 임을 주목)
- 정수 출력 방식은 8비트씩 끊어서 출력한다.
- 각 8비트 마다 나온 2진수를 정수로 변환
- 압축된 정수는 17 ~ 24 번째 비트의 값을 뽑아 낸다.
- 각 열 오른쪽 끝의 숫자는 2진수의 10진값을 의미
- 각 자리의 수가 전혀 다른 숫자가 아님을 주의
3. 이해
- 2진 연산, 논리 및 자릿수 계산 이해, (선택) 쉬프트 연산자 사용을 얼마나 잘할수 있나?
- 자릿수를 끊어서 출력할수 있나?
- 10진수를 2진수로 표현할수 있나?
4. 풀이
#include <time.h>
#include <stdlib.h>
#include <string.h>
#define randomize() srand((unsigned)time(NULL))
char* dec2bin(unsigned long input)
{
char output[33] = "00000000000000000000000000000000";
char output2[33] = "00000000000000000000000000000000";
unsigned long count = 0;
unsigned long temp = input;
while(temp > 0)
{
itoa(temp % 2, &output[count], 10);
count++;
temp /= 2;
}
temp = 32 - count;
count--;
if (count >= 33)
{
printf("Out of range, 32\n");
return NULL;
}
while(temp < 32 )
{
output2[temp] = output[count];
temp++;
count--;
}
return output2;
}
int main()
{
unsigned long i, j, k, input;
char maskchar[33];
char inputchar[33];
char outputchar[33];
while(1)
{
k = 0;
i = 0;
j = 0;
randomize();
rand();
input = rand() * rand() * 4 - 1;
strcpy(maskchar,dec2bin(255 << 16));
strcpy(inputchar,dec2bin(input));
printf("마스크(MASK) : ");
while(i < 4)
{
while(j < 8)
{
printf("%c",maskchar[k]);
k++;
j++;
}
putchar(' ');
i++;
j=0;
}
printf(" 16711680");
printf("\n");
i = 0; j = 0; k = 0;
printf("임의의 정수 : ");
while(i < 4)
{
while(j < 8)
{
printf("%c",inputchar[k]);
k++;
j++;
}
putchar(' ');
i++;
j=0;
}
printf("%13u",input);
printf("\n");
printf("추출된 정수 : ");
printf("%8d %8d %8d %8d ", ((255 << 24 & input) / 16777216), (255 << 16 & input) / 65536 , (255 << 8 & input) / 256 , 255 & input);
printf("%13u",input);
printf("\n");
strcpy(outputchar,dec2bin((255 << 16 & input) / 65536));
i = 0; j = 0; k = 0;
printf("압축된 정수 : ");
while(i < 4)
{
while(j < 8)
{
printf("%c",outputchar[k]);
k++;
j++;
}
putchar(' ');
i++;
j=0;
}
printf("%13u",(255 << 16 & input) / 65536);
putchar('\n');
getchar();
}
return 0;
}
(모범답안)
5. 코드 해석
이번껀 정말 문제 이해도 못해서 많이 헤맷습니다. 결국은 했지만 이걸 실제 제게 문제로 내어버린다면 주어진 시간내에 푼다는건 생각할수가 없네요.
여기서 제일 고생한게 10진수를 2진수로 출력하는 내용입니다. 인터넷에 함수가 있을까 싶어서 찾아봤는데 없더군요. 늦게 나마 itoa 함수를 적절히 쓰면 될거 같은데 그냥 char* 형으로 밀고 나가서 32자리 숫자를 구현했습니다. 숫자를 2로 나눠서 나오는 나머지를 넣는데 방향이 반대가 되므로 다시 바꾸는 루틴이 힘들었습니다.
그렇게 해결할쯤 각 8자리마다 계산하는게 아니라 하나의 숫자라는 사실을 뒤늦게 알고 코드를 전면 수정. 완성했습니다.
- #define randomize() srand((unsigned)time(NULL)) 이 매크로는 rand() 함수를 매번 호출마다 바꾸게 만들기 위해서 정의 했습니다. 실제로 rand() 를 한번더 호출해야지 진짜 rand() 가 되었습니다.
- dec2bin 함수는 직접 만든 함수입니다. 허접하지만 0을 채우는 32비트 char* 형 함수로써 이 문제를 충실히 해결하고 있습니다.
- 32비트 전체를 쓰기 때문에 앞에 부호부가 문제가 될수 있습니다. 따라서 unsigned 형으로 하여 최대자리수를 확보합니다.
- 8자리씩 출력하고 한칸 띄는 알고리듬을 넣었습니다. 보시는데 코드가 조금 지저분 하지 싶습니다.
- 이번껀 조악해서 모법 코드를 같이 넣어 두었습니다. 깔끔하네요.
6. 추가정보
- http://www.winapi.co.kr/clec/cpp1/8-2-1.htm : rand 함수에 대한 설명
- http://winapi.co.kr/clec/cpp1/4-3-1.htm : while 제어문
- http://winapi.co.kr/clec/cpp1/5-2-3.htm : 비트연산자