__builtin_offsetof 运算符的目的和返回类型是什么?

发布于 2024-07-10 18:37:24 字数 125 浏览 5 评论 0原文

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

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

What is the purpose of __builtin_offsetof operator (or _FOFF operator in Symbian) in C++?

In addition what does it return? Pointer? Number of bytes?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

甚是思念 2024-07-17 18:37:24

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

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

It's a builtin provided by the GCC compiler to implement the offsetof macro that is specified by the C and C++ Standard:

GCC - offsetof

It returns the offset in bytes that a member of a POD struct/union is at.

Sample:

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 provides a nice example of where you can use it. I remember having seen it used to implement intrusive lists (lists whose data items include next and prev pointers itself), but i can't remember where it was helpful in implementing it, sadly.

能怎样 2024-07-17 18:37:24

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

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

As @litb points out and @JesperE shows, offsetof() provides an integer offset in bytes (as a size_t value).

When might you use it?

One case where it might be relevant is a table-driven operation for reading an enormous number of diverse configuration parameters from a file and stuffing the values into an equally enormous data structure. Reducing enormous down to SO trivial (and ignoring a wide variety of necessary real-world practices, such as defining structure types in headers), I mean that some parameters could be integers and others strings, and the code might look faintly like:

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

You can now write a general function that reads lines from the config file, discarding comments and blank lines. It then isolates the parameter name, and looks that up in the desc_configuration table (which you might sort so that you can do a binary search - multiple SO questions address that). When it finds the correct config_desc record, it can pass the value it found and the config_desc entry to one of two routines - one for processing strings, the other for processing integers.

The key part of those functions is:

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

This avoids having to write a separate function for each separate member of the structure.

贱人配狗天长地久 2024-07-17 18:37:24

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

#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

The purpose of a built-in __offsetof operator is that the compiler vendor can continue to #define an offsetof() macro, yet have it work with classes that define unary operator&. The typical C macro definition of offsetof() only worked when (&lvalue) returned the address of that rvalue. I.e.

#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
调妓 2024-07-17 18:37:24

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

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

但我确信这存在问题,但我将把它留给感兴趣的读者指出......

As @litb, said: the offset in bytes of a struct/class member. In C++ there are cases where it is undefined, in case the compiler will complain. IIRC, one way to implement it (in C, at least) is to do

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

But I'm sure there are problems this, but I'll leave that to the interested reader to point out...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文