개요
안녕하세요. 이번 글에서는 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;

