2016년 5월 21일 토요일

패딩비트 ( struct ) - 작성 완료

출처 - http://bboy6604.tistory.com/entry/%EA%B5%AC%EC%A1%B0%EC%B2%B4%EC%99%80-Padding-Bit

구조체는 서로 다른 타입의 변수들을 묶어서 새로운 자료형으로 정의 하는 것입니다.
구조체에는 변수, 배열, 포인터,다른 구조체를 포함 할 수 있습니다.

Padding Bit

구조체의 크기는 구조체 안의 변수들을 합한 결과가 아니다.
다음의 코드를 보자.

struct st

{

     int     a;

     char  b;

     short c;

     char  d;

     int     e;

}

int형 2개 8byte,  char형 2개 2byte,  short형 1개 2byte,
총 11byte 이다.
하지만 sizeof 연산자를 통해크기를 출력하면 16byte가 나온다.
이것은 cpu 가 성능 저하를 막기 위해 넣어준 Padding Bit 때문이다.

32 bit cpu 가 데이터를 효율적으로 읽어 들이려면 32 bit 로 읽어야 한다.
그 이하면 필요없는 부분을 읽지 않는 작업을,
그 이상을 읽으면 32bit를 추가하고 나머지를 읽지 않는 작업을 해야한다.
이 과정에서 성능 저하가 일어난다.

그래서 구조체 변수를 읽어 올 때는 컴파일러가 성능 저하를 막기 위해 Padding bit 라는 것을 자동 추가 해준다. ( Padding bit 를 추가해주지 않는 컴파일러도 있다.)
Padding bit 가 추가되는 모습은 아래와 같습니다. (파란색 부분이 Padding bit 입니다.)


40
41
42
43
44
45
46
47
48
49
4A
4B
4C
4D
4E
4F
a
b
 
c
d
 
 
 
e
4byte
4byte
4byte
4byte

Padding bit 만큼 메모리를 낭비 되지만
32 bit 단위로 데이터를 읽어오면 되어 속도는 빨라진다.

Padding bit 는 컴파일러가 자동으로 추가 하는 것이기 때문에 사용자가 사용하지 않을 수있다. #pragma pack(1) 으로 전처리에 명령을 내리면 구조체를 1byte 단위로 읽기 때문에 구조체 구성 변수를 더한 값이 구조체의 크기가 된다.

하지만 #pragma 는 C 표준이 아니기 때문에 이식성이 낮다. 혼자만 쓰는 프로그램이면 #pragma 를 사용해도 크게 문제가 되지 않는다.
하지만 이 프로그램이 통신에 쓰인다면 치명적인 문제점을 안게 된다.
또 한 #pragma pack(1) 이라고 선언해주면 선언 이후의 코드들을 전부 1byte 단위로 데이터를 읽기 때문에 엄청난 성능저하를 가져오게 된다.
이러한 성능 저하를 막기 위해 우리가 1byte 씩 읽어오기를 원하는 코드 전에서 #pragma pack(1)을 선언해주고 그 코드의 끝 부분에 다시 #pragma pack(4) 로 선언해주면 된다. 위의 코드에 적용해보면 다음과 같게 됩니다.



#include <stdio.h>
#pragma pack(push,1);

struct st
{
  int a;
  char b;
  short c;
  char d;
  int e;
};

#pragma pack(4);

int main(void)
{
  struct st st1;
  printf("구조체의 크기: %d\n",sizeof(st1));
  printf("a의 주소: %p, b의 주소: %p, c의 주소: %p, d의 주소: %p, e의 주소 : "
      "%p",&st1.a,&st1.b,&st1.c,&st1.d,&st1.e);

  return 0;
}

하지만 이처럼 수정해주면 32 bit cpu에서는 괜찮지만 8 bit 나 16bit 또는 64 bit cpu 에서 다시 문제가 야기됩니다.
이때는 다음과 같이 해주면 됩니다.


#include <stdio.h>
#pragma pack(push,1);

struct st
{
  int a;
  char b;
  short c;
  char d;
  int e;
};

#pragma pack(pop);

int main(void)
{
  struct st st1;
  printf("구조체의 크기: %d\n",sizeof(st1));
  printf("a의 주소: %p, b의 주소: %p, c의 주소: %p, d의 주소: %p, e의 주소 : "
      "%p",&st1.a,&st1.b,&st1.c,&st1.d,&st1.e);

  return 0;


#pragma pack(push, 1) //1byte 단위로 정렬 방식을 바꾸고 기존정렬방식을 스택에 저장합니다.
#pragma pack(pop)       //스택에 저장한 정렬방식으로 다시 돌립니다.
pack 지시자는 이 후 부터 선언되는 구조체의 정렬 방식을 지정하는 것입니다.
1은 컴파일러가 저장된 메모리에 데이터를 정렬하는 방법을 결정하는 byte의 크기입니다.




댓글 없음:

댓글 쓰기