__builtin_offsetof运算符的用途和返回types是什么?

C ++中__builtin_offsetof运算符(或Symbian中的_FOFF运算符)的用途是什么?

另外它返回什么? 指针? 字节数?

这是由GCC编译器提供的内置函数,用于实现C和C ++标准指定的offsetofmacros:

GCC – offsetof

它返回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提供了一个很好的例子,你可以使用它。 我记得曾经看到它用来实现入侵列表(列表的数据项包括next和prev指针本身),但我不记得它在哪里有帮助实施它,悲哀。

正如@litb指出的和@JesperE所示,offsetof()提供了一个以字节为单位的整数偏移量(作为size_t值)。

你什么时候可以使用它?

一种可能相关的情况是用表格驱动的操作,用于从文件中读取大量不同的configuration参数,并将这些值填充到同样巨大的数据结构中。 减less巨大的琐碎(并忽略了各种各样的必要的现实世界的做法,例如在标题中定义结构types),我的意思是一些参数可以是整数和其他string,代码可能看起来微弱像:

 #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 }, }; 

您现在可以编写一个通用函数来读取configuration文件中的行,放弃注释和空白行。 然后隔离参数名称,并在desc_configuration表中查找(您可以对其进行sorting,以便您可以执行二分search – 多个SO问题解决该问题)。 当find正确的config_desclogging时,它可以将find的值和config_desc条目传递给两个例程之一 – 一个用于处理string,另一个用于处理整数。

这些function的关键部分是:

 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); ... } 

这避免了必须为结构的每个单独成员编写单独的函数。

内build__offsetof运算符的目的是编译器供应商可以继续#define offsetof()macros,但它可以与定义一元运算符&的类一起工作。 offsetof()的典型Cmacros定义仅在(&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 

作为@litb,说:结构/类成员的字节偏移量。 在C ++中,有些情况下它是未定义的,以防编译器投诉。 IIRC,实现它的一种方法(至less在C中)是这样做的

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

但是我确定有这个问题,但我会留给有兴趣的读者指出…