c++ __builtin_offsetof操作符的用途和返回类型是什么?

vc9ivgsu  于 2023-01-03  发布在  其他
关注(0)|答案(4)|浏览(299)

在C++中__builtin_offsetof运算符(或Symbian中的_FOFF运算符)的用途是什么?
另外它返回什么?指针?字节数?

bfhwhh0e

bfhwhh0e1#

它是GCC编译器提供的一个内置函数,用于实现C和C++标准指定的offsetof宏:
GCC-抵销f
它返回POD结构体/联合体成员所在的偏移量(以字节为单位)。
样品:

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提供了一个很好的例子来说明你可以在哪里使用它。我记得我见过它被用来实现侵入式列表(列表的数据项本身包括下一个和上一个指针),但我不记得它在哪里对实现它有帮助,很遗憾。

a1o7rhls

a1o7rhls2#

正如@litb指出和@JesperE所示,offsetof()提供了一个以字节为单位的整数偏移量(作为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表中查找(您可以对它进行排序,以便进行二进制搜索-多个SO问题可以解决这个问题)。当它找到正确的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);
    ...
}

这样就不必为结构的每个单独成员编写单独的函数。

qyswt5oh

qyswt5oh3#

内置__offsetof操作符的目的是编译器供应商可以继续#定义offsetof()宏,但让它与定义一元operator&的类一起工作。offsetof()的典型C宏定义仅在(&lvalue)返回右值的地址时才起作用。

#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
p3rjfoxz

p3rjfoxz4#

正如@litb所说:返回结构体/类成员的偏移量。在C++中,有时候它是未定义的,以防编译器抱怨。IIRC,实现它的一种方法(至少在C中)是

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

但我肯定这里面有问题,但我会留给感兴趣的读者来指出...

相关问题