C/C
[C/C++] 구조체와 공용체 (Struct와 Union)에 대한 고찰 2 - Flexible Array Member(가변 배열 멤버, FAM)
2026. 4. 9. 23:49반응형
이번 시간에는 Flexible Array Member (FAM, 가변 배열 멤버)가 구조체 멤버 변수일 때, 그리고
공용체가 구조체의 멤버 변수일 때, 그 구조체의 전체 크기를 분석해본다.
먼저, 분석할 구조체는 아래와 같다.
(내가 참고한 소스는 아래와 같다.)
https://github.com/strongswan/strongswan/blob/master/src/stroke/stroke_msg.h#L179
truct stroke_msg_t {
/* length of this message with all strings */
uint16_t length;
/* type of the message */
enum {
ZERO,
ONE,
} type;
int output_verbosity;
union {
struct {
char *name;
} initiate;
struct {
char *start;
char *end;
} terminate_srcip;
};
/* length of the string buffer */
uint16_t buflen;
/* string buffer */
char buffer[];
};
■ 구조체 분석
먼저, 멤버별 크기(64비트 기준) 및 오프셋을 이론적으로 분석해보자. 결론만 말하면, 이 구조체의 총 크기는 40 bytes 이다.
struct stroke_msg_t {
unsigned short length; // [offset: 0] 2 bytes
// [offset: 2] 패딩 2 bytes (enum int 정렬 맞추기)
enum {
STR_INITIATE,
STR_ROUTE,
} type; // [offset: 4] 4 bytes (enum → int 크기)
int output_verbosity; // [offset: 8] 4 bytes
// [offset: 12] 패딩 4 bytes (포인터 8byte 정렬 맞추기)
union { // [offset: 16] 16 bytes (가장 큰 멤버 기준)
struct {
char *name; // [offset: 16] 8 bytes (포인터)
} initiate; // 합계: 8 bytes
struct {
char *start; // [offset: 16] 8 bytes (포인터)
char *end; // [offset: 24] 8 bytes (포인터)
} terminate_srcip; // 합계: 16 bytes
}; // union 크기 = max(8, 16) = 16 bytes
unsigned short buflen; // [offset: 32] 2 bytes
// [offset: 34] 패딩 6 bytes (구조체 정렬 8bytes 맞추기)
char buffer[]; // [offset: 40] 0 bytes (Flexible Array Member)
};
// sizeof(struct stroke_msg_t) = 40 bytes
여기서 buffer 변수는 Flexible Array Member로써 크기를 차지하지 않는다. 이 변수는 sizeof에 포함되지 않으며, malloc으로 동적 할당 시 뒤에 가변 버퍼를 붙이는 패턴으로 사용된다.
그리고 이 패턴의 변수를 활용하여 가변 배열(Flexible Array)을 추가하는 예제는 아래와 같다.
size_t extra = 128;
struct stroke_msg_t *msg = malloc(sizeof(*msg) + extra);
msg->buflen = extra;
// msg->buffer[0..127] 사용 가능
구조체에 패딩이 생긴 이유를 자세히 나타내면 아래와 같다.
unsigned short length; // [offset: 0] 2 bytes → 다음 멤버가 enum(int, 4byte 정렬)
// [offset: 2] 패딩 2 bytes → offset 4 맞추기 위해
enum { ... } type; // [offset: 4] 4 bytes → 다음 멤버도 int(4byte 정렬)
int output_verbosity; // [offset: 8] 4 bytes → 다음 멤버가 포인터(8byte 정렬)
// [offset:12] 패딩 4 bytes → offset 16 맞추기 위해
union { ... }; // [offset:16] 16 bytes → 다음 멤버가 short(2byte 정렬)
unsigned short buflen; // [offset:32] 2 bytes
// [offset:34] 패딩 6 bytes → 구조체 전체 크기를
// 가장 큰 멤버(포인터, 8byte)의 배수로 맞추기 위해
구조체 자체의 크기는 내부에서 가장 정렬 단위가 큰 멤버(여기서는 포인터 = 8 bytes)의 배수가 되어야 한다.
참고로 먼저, 우분투(Ubuntu) 시스템이 64비트(x86_64)인지 32비트(i386/i686)인지 확인하는 방법은 getconf 명령어로 확인한다.
$ getconf LONG_BIT
64
그리고 실제로 저 구조체 크기를 출력한 결과 40 bytes가 나오는 걸 확인했다.
int main (void) {
printf("size: %d\n", sizeof(struct stroke_msg_t));
return 0;
}
출력결과
size: 40반응형
'C > C' 카테고리의 다른 글
| [C/C++] 공유 라이브러리 (Shared Library) 기본 예제 (0) | 2026.04.13 |
|---|---|
| [C][소켓] socket read 중 close() 시 안전하게 구현하기 (0) | 2026.03.25 |
| [C][소켓] 메인스레드가 recv 하는 동안 fd가 close되면 어떻게 될까? (0) | 2024.09.04 |
| [C/C++] __attribute__((packed))에 대한 이해 (1) | 2024.03.28 |
| [C] 파일입출력 예제 (0) | 2023.03.31 |
