본문 바로가기

카테고리 없음

C언어 구조체 멤버 정렬(alignment) 사용

https://www.yes24.com/Product/Goods/117080938

C 언어 코딩 도장  - 예스24

프로그래밍은 연습으로 배우는 것이다!가장 깊이 있는 C 언어 입문서C 언어의 난해하고 까다로운 주제도 생략하지 않고 단계별로 차근차근 설명한다. 개념을 생략하고 쉬운 책이 되는 것보단 제

www.yes24.com

 
공부한것을 정리한 내용입니다.
 
 
 
C언어 컴파일러는 CPU가 메모리의 데이터에 효율적으로 접근할 수 있도록 구조체를 일정한 크기로 정렬한다. 예를 들어 구조체 크기가 15,17 바이트가 되면 접근 효율이 떨어지므로 2, 4, 8, 16 바이트 단위로 정렬을 한다. 하지만 예외가 있는데 사진파일을 저장할 때마다 정렬이 발생해 사진이 깨질 수도 있고 네트워크 데이터를 전송할 때 몇바이트씩 보내는 정해진 규약이있는데 이때 정렬이 발생해버리면 곤란하게 된다. 이때 구조체 정렬을 원하는 만큼 크기를 조절해야 한다.
 
 
예를들어 구조체를 정의할 때 위아래로 #pragma pack(push, 2) 하고 #pragma pack(pop)을넣어준다. 
 
1. #pragma pack(push,2)은 2바이트 크기로 정렬해주고
2. #pragma pack(pop)은 #pragma pack(push,2)한번 사용하면 그 아래오는 모든 구조체에 영향을 주므로 정렬을 설정한 뒤에 #pragma pack(pop)을 사용하여 설정을 이전 상태로 되돌린다.
 

#include <stdio.h>

#pragma pack(push,2) // 2바이트 크기로 정렬
struct PacketHeader{
  char flags; // 1바이트
  int seq; // 4바이트
};
#pragma pack(pop) // pop을 사용해 정렬이전 상태로 되돌림

int main()
{
  struct PacketHeader header;

  printf("%d\n", sizeof(header.flags)); // char flags 1바이트
  printf("%d\n", sizeof(header.seq)); // int seq 4바이트 
  // 2바이트 단위로 정렬 했으므로 구조체 전체크기는 4+2= 6바이트 
  printf("%d\n", sizeof(header)); 
  
  return 0;

}

 
이때 pack을 2 바이트 단위로 정렬하면서 남는공간(패딩)없이  자료형 크기 그대로 메모리에 올라간다.

 
offsetof를 사용해 해당멤버의 상대위치를 알 수 있다 2바이트 크기로 정렬 했으니 2가 반환된다. 첫 멤버의 상대 위치는 0이다.
 사용할려면 
offsetof(struct 구조체, 멤버)
offsetof(구조체별칭, 멤버)
 

#include <stdio.h>
#include <stddef.h> // offsetof 매크로가 정의된 헤더파일

#pragma pack(push,2) // 2바이트 크기로 정렬
struct PacketHeader{
  char flags; // 1바이트
  int seq; // 4바이트
};
#pragma pack(pop) // pop을 사용해 정렬이전 상태로 되돌림

int main()
{
  

  // 첫 멤버의 상대위치는 0
  printf("%d\n", offsetof(struct PacketHeader, flags));
  // 2바이트 크기로 정렬했으니 멤버의 위치는 2
  printf("%d\n", offsetof(struct PacketHeader, seq));

  return 0;
}