__builtin_offsetof 연산자의 목적과 반환 유형은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/400116

  •  03-07-2019
  •  | 
  •  

문제

C ++의 __builtin_offsetof 연산자 (또는 Symbian의 _foff 연산자)의 목적은 무엇입니까?

또한 무엇이 반환됩니까? 바늘? 바이트 수?

도움이 되었습니까?

해결책

GCC 컴파일러가 제공하는 내장입니다. offsetof C 및 C ++ 표준에 의해 지정된 매크로 :

GCC- 오프셋

포드 구조/유니언의 구성원이있는 바이트로 오프셋을 반환합니다.

견본:

struct abc1 { int a, b, c; };
union abc2 { int a, b, c; };
struct abc3 { abc3() { } int a, b, c; }; // non-POD
union abc4 { abc4() { } int a, b, c; };  // non-POD

assert(offsetof(abc1, a) == 0); // always, because there's no padding before a.
assert(offsetof(abc1, b) == 4); // here, on my system
assert(offsetof(abc2, a) == offsetof(abc2, b)); // (members overlap)
assert(offsetof(abc3, c) == 8); // undefined behavior. GCC outputs warnings
assert(offsetof(abc4, a) == 0); // undefined behavior. GCC outputs warnings

@jonathan은 사용할 수있는 곳의 좋은 예를 제공합니다. 나는 그것이 침입적인 목록을 구현하는 데 익숙한 것을 본 것을 기억하지만 (데이터 항목에 Next 및 Prev Pointers 자체가 포함 된 목록), 슬프게도 구현하는 데 도움이되는 곳을 기억할 수 없습니다.

다른 팁

@litb가 지적하고 @jespere가 표시하는 것처럼, 오프셋 ()는 바이트로 정수 오프셋을 제공합니다 ( size_t 값).

언제 사용할 수 있습니까?

관련이있는 경우 중 하나는 파일에서 막대한 다양한 구성 매개 변수를 읽고 값을 똑같이 거대한 데이터 구조로 채우는 테이블 중심 작업입니다. 매우 사소한 것으로 줄이면서 (헤더에서 구조 유형을 정의하는 것과 같은 다양한 필요한 실제 관행을 무시할 때) 일부 매개 변수는 정수 및 다른 문자열 일 수 있으며 코드가 희미하게 보일 수 있음을 의미합니다.

#include <stddef.h>

typedef stuct config_info config_info;
struct config_info
{
   int parameter1;
   int parameter2;
   int parameter3;
   char *string1;
   char *string2;
   char *string3;
   int parameter4;
} main_configuration;

typedef struct config_desc config_desc;
static const struct config_desc
{
   char *name;
   enum paramtype { PT_INT, PT_STR } type;
   size_t offset;
   int   min_val;
   int   max_val;
   int   max_len;
} desc_configuration[] =
{
    { "GIZMOTRON_RATING", PT_INT, offsetof(config_info, parameter1), 0, 100, 0 },
    { "NECROSIS_FACTOR",  PT_INT, offsetof(config_info, parameter2), -20, +20, 0 },
    { "GILLYWEED_LEAVES", PT_INT, offsetof(config_info, parameter3), 1, 3, 0 },
    { "INFLATION_FACTOR", PT_INT, offsetof(config_info, parameter4), 1000, 10000, 0 },
    { "EXTRA_CONFIG",     PT_STR, offsetof(config_info, string1), 0, 0, 64 },
    { "USER_NAME",        PT_STR, offsetof(config_info, string2), 0, 0, 16 },
    { "GIZMOTRON_LABEL",  PT_STR, offsetof(config_info, string3), 0, 0, 32 },
};

이제 구성 파일에서 줄을 읽고 주석을 버리고 빈 줄을 읽는 일반적인 기능을 작성할 수 있습니다. 그런 다음 매개 변수 이름을 분리하고 desc_configuration 테이블 (이진 검색을 수행 할 수 있도록 정렬 할 수 있습니다. 그것이 올바른 것을 찾을 때 config_desc 기록, 발견 한 가치와 config_desc 두 개의 루틴 중 하나에 입력 - 하나는 문자열을 처리하고 다른 하나는 정수 처리를위한 것입니다.

이러한 기능의 핵심 부분은 다음과 같습니다.

static int validate_set_int_config(const config_desc *desc, char *value)
{
    int *data = (int *)((char *)&main_configuration + desc->offset);
    ...
    *data = atoi(value);
    ...
}

static int validate_set_str_config(const config_desc *desc, char *value)
{
    char **data = (char **)((char *)&main_configuration + desc->offset);
    ...
    *data = strdup(value);
    ...
}

이것은 구조의 각 별도 구성원에 대해 별도의 기능을 작성하지 않아도됩니다.

내장 된 __offsetof 운영자의 목적은 컴파일러 공급 업체가 #define을 계속 오프셋 () 매크로를 계속 만들 수 있지만 단일 연산자를 정의하는 클래스와 함께 작동 할 수 있다는 것입니다. Offsetof ()의 일반적인 C 매크로 정의는 (& lvalue)가 해당 rvalue의 주소를 반환했을 때만 작동했습니다. 즉

#define offsetof(type, member) (int)(&((type *)0)->member) // C definition, not C++
struct CFoo {
    struct Evil {
        int operator&() { return 42; }
    };
    Evil foo;
};
ptrdiff_t t = offsetof(CFoo, foo); // Would call Evil::operator& and return 42

@litb와 마찬가지로 다음과 같이 말했습니다 : 구조물/클래스 멤버의 바이트 오프셋. C ++에는 컴파일러가 불만을 제기 할 경우 정의되지 않은 경우가 있습니다. IIRC, 그것을 구현하는 한 가지 방법은 (적어도 C에서)

#define offsetof(type, member) (int)(&((type *)0)->member)

그러나 나는 이것에 문제가 있다고 확신하지만, 관심있는 독자에게 그것을 지적하기 위해 그것을 떠날 것입니다 ...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top