[C++/Win32] offsetof, _countof, std::size : 구조체, 배열 분석 함수

[C++/Win32] offsetof, _countof, std::size : 구조체, 배열 분석 함수

개요

안녕하세요. 이번 글에서는 C, C++ 에서 구조체 분석을 할 때 자주 사용되는 함수에 대해 알아보겠습니다. offsetof와 _countof 매크로 함수는 구조체에서 특정 변수의 위치나, 배열의 개수를 얻고 싶을 때 자주 사용하는 함수 입니다. 이 두 함수를 알고 있으면 나중에 네트워크 패킷이나 통신 프로토콜을 다룰 때 편하게 분석 할 수 있습니다.

offsetof

offsetof는 구조체의 시작 부분에서 멤버의 오프셋을 검색하는 매크로 입니다. offset 매크로를 사용하기 위해서는 cstddef 또는 C에서는 stddef 헤더를 include 해야하며, 첫 번째엔 구조체 이름을, 두 번째엔 멤버의 이름을 입력하면 됩니다.

// <cstddef>
// <stddef.h>
size_t offsetof(
   structName,
   memberName
);

아래처럼 ST_TEST 구조체가 있을 때 각 멤버의 구조체에서 offset 값을 구하려면 아래와 같이 코드를 만들어줍니다.

#include <iostream>
#include <cstddef> // offsetof 사용을 위해 필요
//#include <stddef.h> // offsetof 사용을 위해 필요

#pragma pack(push, 1)
struct ST_TEST
{
    int iA;
    char c;
    int iB[4];
    int iC;
};
#pragma pack(pop)

int main()
{
    std::cout << "iA의 위치: " << offsetof(ST_TEST, iA) << " 바이트\n";
    std::cout << "c의 위치: " << offsetof(ST_TEST, c) << " 바이트\n";
    std::cout << "iB의 위치: " << offsetof(ST_TEST, iB) << " 바이트\n";
    std::cout << "iB[1]의 위치: " << offsetof(ST_TEST, iB[1]) << " 바이트\n";
    std::cout << "iB[2]의 위치: " << offsetof(ST_TEST, iB[2]) << " 바이트\n";
    std::cout << "iB[3]의 위치: " << offsetof(ST_TEST, iB[3]) << " 바이트\n";
    std::cout << "iC의 위치: " << offsetof(ST_TEST, iC) << " 바이트\n";
    return 0;
}

위 코드에 대해 아래와 같이 출력합니다.

_countof

_countof 는 정적으로 할당된 배열의 요소 수를 계산하는 매크로 입니다. _countof 매크로를 사용하려면 stdlib 헤더를 include 해야하며, _countof에 배열 변수명을 입력 해야합니다.

// #include <stdlib.h>
#define _countof(array) (sizeof(array) / sizeof(array[0]))

실제 코드는 아래와 같습니다.

#include <iostream>
#include <stdlib.h> // _countof 사용을 위해 필요

int main()
{
    // 전통적인 방식 (전체 바이트 크기 / 한 칸의 바이트 크기)
    int iArray[10] = {0,1,2,3,4,5,6,7,8,9};
    size_t cStyleCount = sizeof(iArray) / sizeof(iArray[0]);

    // Windows / VC++ 방식
    size_t vcCount = _countof(iArray);

    // 표준 방식
    size_t stdCount = std::size(iArray);

    std::cout << "전통적인 C 방식 iB 배열 개수: " << cStyleCount << "개" << std::endl; // 출력: 10
    std::cout << "VC++ 방식 iB 배열 개수: " << vcCount << "개" << std::endl; // 출력: 10
    std::cout << "표준 방식 iB 배열 개수: " << stdCount << "개" << std::endl; // 출력: 10

    return 0;
}

출력 결과는 아래와 같습니다.

_countof가 아니더라도 std::size 함수를 사용해도 같은 결과를 출력합니다. std::size는 C++ 17부터 표준 라이브러리에 들어간 함수지만 _coutof와 동작이 동일합니다. 해당 함수를 사용하면 _count와 다르게 배열과 컨테이너 모두 사용이 가능하므로 C++ 17 이상이고 표준을 따른다면 std::size를 사용하는 것도 추천드립니다.

template <class C> constexpr auto size(const C& c)
    -> decltype(c.size());
template <class T, size_t N> constexpr size_t size(const T (&array)[N]) noexcept;

offsetof MSDN

_countof MSDN

std::size MSDN

github