본문 바로가기

차장님의 이야기

C++의 offsetof 매크로 뜯어보기

C++에서 Reflection을 구현하기 란 내용을 보던 중, 신기한 함수가 있어 바로 XCode를 열고 코드를 확인을 할려고 하였으나

"?"  란 문자가 나오면서 나는 몰라... 라고 하는 XCode를 보았다..

 

그래서 조금만 더 검색해서 데이터를 결국엔 찾았다.

 

Cppreference.com 에서 정의는

 


The macro offsetof expands to an integer constant expression of type size_t, the value of which is the offset, in bytes, from the beginning of an object of specified type to its specified member, including padding if any.


이라고 한다. 즉 offsetof는 매크로로 정의가 되어 있고, 객체의 멤버의 위치를 반환 한다고 한다.

 

#include <stdio.h>
#include <stddef.h>
 
struct S {
    char c;
    double d;
};
 
int main(void)
{
    printf("the first element is at offset %zu\n", offsetof(struct S, c));
    printf("the double is at offset %zu\n", offsetof(struct S, d));
}

코드는 이렇게 되어 있고, 실행 결과는

the first element is at offset 0
the double is at offset 8

위 처럼 나온다고 한다.

 

char은 크기가 1, double의 크기는 8이므로 컴파일러 최적화에 의해서 S 구조체는 16바이트의 크기를 가진다.

offsetof(struct S, d)의 값이 1이 나오길 원한다면

struct S {
    double d;
    char c;
};

이 처럼 해야한다.

 

offsetof 코드는

아래 처럼 정의가 되어있다 (MSVC 기준)

#define offsetof(s, m) (size_t)&(((s *)0)->m)

s는 struct 즉 Type 가 될 것이고

m은 member, 즉 변수 이다.

최초 주소지를 0번지를 지정하고 캐스팅 연산 후 결과 값을 반환 해주는 것 이다.

 

의외로 단순한데 이걸 매크로로 심플하고 간단하게 만든것에 대단하다는 걸 느꼈다..

나는 RTTI 같은, C#에 있는 nameof 같은 기능을 이용 했을 것 같았는데 그런게 전혀 아니라 단순 포인터 연산으로 구현을 했다는게 대단했다.