C++中__builtin_offsetof运算符(或Symbian中的_FOFF运算符)的用途是什么?
它还有什么回报?指针?字节数?
正如@litb指出并且@JesperE所示,offsetof()提供以字节为单位的整数偏移量(作为size_t
值).
你何时可以使用它?
可能相关的一种情况是表驱动操作,用于从文件中读取大量不同的配置参数并将值填充到同样巨大的数据结构中.将大量减少到极少数(并忽略各种必要的现实实践,例如在头文件中定义结构类型),我的意思是一些参数可能是整数和其他字符串,代码可能看起来像:
#includetypedef 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); ... }
这避免了必须为结构的每个单独成员编写单独的函数.
它是GCC编译器提供的内置offsetof
函数,用于实现C和C++标准指定的宏:
海湾合作委员会 - 抵消
它返回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指针本身的列表),但遗憾的是我无法记住它在实现它时有何帮助.
内置__offsetof运算符的目的是编译器供应商可以继续#define一个offsetof()宏,但它可以使用定义一元运算符&的类.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