https://m.blog.naver.com/PostView.nhn?blogId=tipsware&logNo=221279743314&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F




1. 실습 내용
아래와 같이 int 자료형으로 선언된 변수의 값을 바이트 단위로 출력하는 프로그램을 만들어 보도록 하겠습니다. 

int value = 0x12345678;


2. 실습 예제의 출력 결과
실습 예제를 보기 전에 '실습 내용'을 보고 스스로 만들어 보려고 노력하는 것이 공부에 더 도움이 됩니다. 그래서 실습 예제 코드를 보여주기 전에 실습 예제의 출력 결과를 먼저 보여드릴 테니 아래처럼 동작하게 만들어 보세요. ('리틀 엔디언(Little Endian)'이 적용된 시스템에서 출력한 결과입니다.)

value = 0x12345678, byte list = 0x78, 0x56, 0x34, 0x12, 계속하려면 아무 키나 누르십시오 . . .



3. 실습 예제 코드
이 실습은 다양한 형태로 구현이 가능합니다. 그래서 실습을 기술별로 나눠서 하나씩 소개하도록 하겠습니다. 그리고 실습을 하기 전에 메모리 정렬 방식에 대해서 잘 모르신다면 아래의 글을 꼭 읽어보시기 바랍니다.


[ 포인터를 사용해서 구현 ]
포인터는 대상의 실제 자료형과 상관없이 자신이 사용하고 싶은 크기로 대상의 값을 출력할 수 있습니다. 즉, value 변수는 int형이지만 아래와 같이 char * 형식의 포인터를 선언해서 value 변수의 시작 주소를 저장하면 1바이트 단위로 값을 출력할 수 있습니다.

value 변수는 int 자료형이라서 &를 사용하여 주소를 계산하면 해당 주솟값은 int *형식의 자료형으로 처리됩니다. 그런데 포인터의 자료형이 char *라서 일치하지 않아 경고가 발생하기 때문에 char * 자료형으로 형변환을 했습니다.

char *p = (char *)&value;

이렇게 포인터 변수 p가 value 변수의 시작 주소를 저장하게 되면 *p는 value 변수의 첫 번째 바이트를 사용하게 되고 *(p+1)을 하게 되면 value 변수의 두 번째 바이트, *(p+2)을 하게 되면 value 변수의 세 번째 바이트, *(p+3)을 하게 되면 value 변수의 네 번째 바이트를 사용하게 됩니다.

따라서 반복문을 아래와 같이 사용하여 printf 함수로 출력하면 value 변수의 값을 바이트 단위로 출력할 수 있습니다.

for (i = 0; i < 4; i++) { printf("0x%x, ", *(p + i)); }

따라서 위에서 이야기한 코드를 가지고 실습 코드를 구성해보면 다음과 같습니다.

#include <stdio.h> // printf 함수를 사용하기 위해! int main() { int value = 0x12345678, i; char *p = (char *)&value; printf("value = 0x%x, byte list = ", value); for (i = 0; i < 4; i++) { printf("0x%x, ", *(p + i)); } printf("\n"); return 0; }

반복문에 사용된 printf 함수는 아래와 같이 구성해도 됩니다.

printf("0x%x, ", *p++);


[ 배열을 사용해서 구현 ]
value 변수와 동일한 크기의 char 항목을 사용하는 배열 변수를 선언하고 이 배열 변수에 value 변수의 값을 복사하면 바이트 단위로 value 변수의 값을 출력할 수 있습니다. 그런데 배열에 자료형이 다른 변수의 값을 직접 대입할 수 없기 때문에 memcpy 함수를 사용해서 복사해야 합니다.

이 방법을 사용하는 실습 코드는 다음과 같습니다.

#include <stdio.h> // printf 함수를 사용하기 위해! #include <string.h> // memcpy 함수를 사용하기 위해! int main() { int value = 0x12345678, i; char data[4]; memcpy(data, &value, 4); // value 변수를 data 변수에 복사한다. printf("value = 0x%x, byte list = ", value); for (i = 0; i < 4; i++) { printf("0x%x, ", data[i]); } printf("\n"); return 0; }


[ Shift 연산자와 Bit 연산자를 사용해서 구현 ]
value 변수의 값을 바이트 단위로 보고 싶다면 일단 아래와 같이 비트 연산을 하면 됩니다.

첫 번째 바이트의 값을 확인하고 싶을 때 : value & 0x000000FF -> 0x00000078 두 번째 바이트의 값을 확인하고 싶을 때 : value & 0x0000FF00 -> 0x00005600 세 번째 바이트의 값을 확인하고 싶을 때 : value & 0x00FF0000 -> 0x00340000 네 번째 바이트의 값을 확인하고 싶을 때 : value & 0xFF000000 -> 0x12000000

첫 번째 바이트 값은 1바이트 범위의 값이기 때문에 상관없지만 두 번째, 세 번째, 네 번째 값은 1 바이트 단위의 값으로 변경하려면 시프트 연산자를 사용하여 아래와 같이 왼쪽에서 오른쪽으로 비트를 옮겨서 마지막 바이트에 위치 시켜야 합니다.

0x00005600 >> 8 -> 0x00000056 0x00340000 >> 16 -> 0x00000034 0x12000000 >> 24 -> 0x00000012

위 내용을 코드로 구성해서 실습 코드를 완성해보면 다음과 같습니다.

#include <stdio.h> // printf 함수를 사용하기 위해! int main() { int value = 0x12345678, i; printf("value = 0x%x, byte list = ", value); for (i = 0; i < 4; i++) { printf("0x%x, ", (value & (0xFF << i*8)) >> i*8); } printf("\n"); return 0; }


[ Union 문법을 사용해서 구현 ]
이 방법은 배열을 사용하는 방법과 같은 원리입니다. 공용체는 동일한 데이터를 다른 자료형으로 사용하는 기술이기 때문에 int와 크기가 같은 char[4]를 공용체로 함께 선언하여 value 변수에서 넘겨받은 값을 char[4] 형식으로 출력하는 방법입니다.

공용체를 사용하는 실습 코드를 완성해보면 다음과 같습니다.

#include <stdio.h> // printf 함수를 사용하기 위해! union TransByte { int value; char data[4]; }; int main() { int value = 0x12345678, i; union TransByte temp; temp.value = value; printf("value = 0x%x, byte list = ", value); for (i = 0; i < 4; i++) { printf("0x%x, ", temp.data[i]); } printf("\n"); return 0; }