2011년7월5일_숙제_배열을 가리키는 구조체(struct)로 일정 양식(format)에 맞게 엑세스

 

● 선생님께서 불러주신대로 친 소스코드

   1:  //2011년7월5일_숙제_배열을 가리키는 구조체(struct)로 일정 양식(format)에 맞게 엑세스
   2:  #include <stdio.h>
   3:   
   4:  typedef struct 
   5:  {
   6:      int a;
   7:      int b;
   8:      int c;
   9:  } EMB;
  10:   
  11:  int main()
  12:  {
  13:      int array[6];
  14:      EMB *stp;
  15:      unsigned char *ucp;
  16:   
  17:      stp = (EMB *)array;
  18:      ucp = (unsigned char *)array;
  19:   
  20:      *ucp = 0x64;
  21:      ++ucp;
  22:      *ucp = 0x00;
  23:      ++ucp;
  24:      *ucp = 0x00;
  25:      ++ucp;
  26:      *ucp = 0x00;
  27:      
  28:      ++ucp;
  29:      *ucp = 0x63;
  30:      ++ucp;
  31:      *ucp = 0x00;
  32:      ++ucp;
  33:      *ucp = 0x00;
  34:      ++ucp;
  35:      *ucp = 0x00;
  36:      
  37:      ++ucp;
  38:      *ucp = 0x62;
  39:      ++ucp;
  40:      *ucp = 0x00;
  41:      ++ucp;
  42:      *ucp = 0x00;
  43:      ++ucp;
  44:      *ucp = 0x00;
  45:   
  46:      ++ucp;
  47:      *ucp = 0x61;
  48:      ++ucp;
  49:      *ucp = 0x00;
  50:      ++ucp;
  51:      *ucp = 0x00;
  52:      ++ucp;
  53:      *ucp = 0x00;
  54:   
  55:      stp = (EMB *)&array[1];
  56:      
  57:      printf("array[0] %d\n", array[0]);
  58:      printf("array[1] %d\n", array[1]);
  59:      printf("array[2] %d\n", array[2]);
  60:      printf("stp->a %d\n", stp->a);    
  61:      printf("stp->b %d\n", stp->b);    
  62:      printf("stp->c %d\n", stp->c);    
  63:      
  64:      ucp = (unsigned char *)array;
  65:      ++ucp;
  66:      stp = (EMB *)ucp;
  67:   
  68:      printf("stp->a %d\n", stp->a);    
  69:      printf("stp->b %d\n", stp->b);    
  70:      printf("stp->c %d\n", stp->c);    
  71:      return 0;
  72:  }


17행에서 구조체포인터 stp는 array의 시작을 가리키고,
18행에서 unsigned char 포인터 ucp도 array의 시작을 가리킨다.

*ucp로 array배열에 순서대로 0x64, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00 을 넣는다.
메모리(stack)는 아래와 같이 된다.

 

● 메모리상태

image

일반변수가 쌓이는 순서와 달리 배열의 인덱스들은 거꾸로 되어 있다는 것에 유의하자.
인덱스가 커질수록 인입함수의 EBP의 값이 저장된 곳으로 돌진한다.


● 소스코드 분석 들어갑니다

   1:      stp = (EMB *)array;
   2:      ucp = (unsigned char *)array;


image

한 마리의 암컷사자를 두고 두 마리의 숫사자가 대치하고 있는 상황과 유사하다.
EMB구조체 포인터변수 stp와 unsigned char 포인터변수 ucp가 모두 array의 주소를 갖고 있다.

 

   1:      stp = (EMB *)&array[1];
   2:      
   3:      printf("array[0] %d\n", array[0]);
   4:      printf("array[1] %d\n", array[1]);
   5:      printf("array[2] %d\n", array[2]);
   6:      printf("stp->a %d\n", stp->a);    
   7:      printf("stp->b %d\n", stp->b);    
   8:      printf("stp->c %d\n", stp->c);


image

image

stp는 array[1]을 가리키게 되고,


 image

stp->a를 읽으면 stp가 가리키는 곳의 시작부터 a의 크기만큼(int니 4Bytes)를 읽어 들이게 된다. (array[1]의 값)
stp->b를 읽으면 stp가 가리키는 곳의 5Bytes째(a크기 + 1) 부터 읽기 시작하여 b의 크기만큼 읽어 들이게 된다. (array[2]의 값)
stp->c를 읽으면 stp가 가리키는 곳의 9Bytes째(a와 b의 크기 +1) 부터 읽기 시작하여 c의 크기만큼 읽어 들이게 된다. (array[2]의 값)


   1:      ucp = (unsigned char *)array;
   2:      ++ucp;
   3:      stp = (EMB *)ucp;
   4:   
   5:      printf("stp->a %d\n", stp->a);    
   6:      printf("stp->b %d\n", stp->b);    
   7:      printf("stp->c %d\n", stp->c);

image 

다시 ucp의 값을 array배열의 시작주소로 초기화한 뒤에,
ucp의 값을 1증가시키고 stp가 ucp를 가리키게 하면,
엄청나게 큰 값이 나온다. 왜 그런지 아래의 메모리상태도를 보고 분석하자.


image

마치 구조체 EMB를 슬라이드로 하여 array를 투영하는 것과 같다.
%d형식지정자로 출력하면 값확인이 어려우니..%08X형식지정자로 16진수값을 확인하는 것이 좋다.

   1:      printf("stp->a %08X\n", stp->a);    
   2:      printf("stp->b %08X\n", stp->b);    
   3:      printf("stp->c %08X\n", stp->c);

image

big endian과 little endian개념이 없는 분들은 보고 잘 이해가 안되 혼란스러우실 겁니다.
의문이 있으면 댓글 남겨주세요.

이렇게 구조체를 선언하지 않고 구조체를 가리키는 포인터변수만 선언하여 1차원배열(버퍼)을 일정양식에 맞게 엑세스하고 싶을 때,
사용하면 좋겠다. hexaview프로젝트에 적용한다면 파일포맷에 맞게 값을 읽고 쓸 수 있을 것이다.
예를 들어, bmp파일의 경우 헤더부분에 RAW DATA의 크기가 있는데 그 부분을 읽는다고 포인터를 이동하는게 아니라.
             구조체의 값만 읽으면 끝나니 매우 편리한 방법이라고 할 수 있겠다.

잇힝!