C++ 가변 길이 구조체

💡 Quotation

Flexible array members were officially standardized in C99. In practice, compilers (e.g., GCC, Microsoft’s) provided them well before C99 was standardized.

Flexible array members are not officially part of C++, but language extensions are widely available.

소켓 프로그래밍 중 가변 길이의 데이터를 보낼 방법을 찾다가 발견하게 되었습니다. 위 글처럼 C99에 공식적으로 표준화가 되었으며 C++ 에서는 공식적이지는 않지만 사용할 수 있습니다.

메모리에 연속된 공간으로 할당하며 통신할 때 유용하게 사용될 수 있습니다.

Declaration

반드시 구조체의 맨 마지막에 배열을 선언해야 하며 가변이므로 배열의 수는 비워둡니다.

1
2
3
4
5
6
7
typedef struct _Packet
{
    unsigned int  totalSize;
    unsigned int  sentSize;
    unsigned int  currentSize;
    unsigned char payload[];
} Packet;

💡 Tips

위 구조체의 사이즈 sizeof(Packet)의 값은 12 byte가 됩니다.

코드
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <iostream>

typedef struct _Packet
{
    unsigned int  totalSize;
    unsigned int  sentSize;
    unsigned int  currentSize;
    unsigned char payload[];
} Packet;

int main()
{
    std::cout << "Packet 구조체의 사이즈 : " <<  sizeof(Packet) << std::endl;

    return 0;
}

실행결과 : Packet 구조체의 사이즈 : 12

Allocation

C 스타일의 malloc 함수 또는 C++ 스타일의 new 연산자를 사용해서 할당을 해줍니다.

여기서, 기본 구조체의 사이즈 sizeof(Packet)payload의 사이즈를 모두 더한 값으로 할당하면 됩니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

typedef struct _Packet
{
    unsigned int  totalSize;
    unsigned int  sentSize;
    unsigned int  currentSize;
    unsigned char payload[];
} Packet;

int main()
{
    const unsigned int PAYLOAD_SIZE = 527;
    const unsigned int PACKET_SIZE = sizeof(Packet) + PAYLOAD_SIZE;
    Packet *data = (Packet*)new unsigned char[PACKET_SIZE];
    
    ...

    delete[] data;
    return 0;
}
  • 13: 패킷의 페이로드 사이즈 정의 (가변)
  • 14: 원래의 패킷 사이즈와 페이로드 사이즈 모두 더한 값
  • 15: C++ 스타일로 동적 할당
  • 19: 동적 할당 해제

Conclusion

별다른 헤더 파일 없이 바로 작성 및 빌드가 가능하며 패킷 구성할 때 정말 유용하게 쓰입니다. 이렇게 구현하지 않았다면 패킷의 헤더와 페이로드 부분을 각각 분리하여 작성했을 것이고 소켓에서도 두 번의 send/recv를 했을 것 같습니다.