如何使用`offsetof`以标准符合方式访问字段?

sky*_*ing 10 c pointers offsetof language-lawyer

假设我有一个结构并将偏移量提取给成员:

struct A {
    int x;
};

size_t xoff = offsetof(A, x);
Run Code Online (Sandbox Code Playgroud)

如果指针以struct A标准符合方式提取成员,我该怎么办?当然假设我们有struct A*正确的偏移量.一种尝试是做类似的事情:

int getint(struct A* base, size_t off) {
    return *(int*)((char*)base + off); 
}
Run Code Online (Sandbox Code Playgroud)

这可能会工作,但要注意的例子指针算术只有似乎标准中定义,如果指针是相同的阵列(或一个过去的结束)的指针,这不一定是这种情况.从技术上讲,构造似乎依赖于未定义的行为.

另一种方法是

int getint(struct A* base, size_t off) {
    return *(int*)((uintptr_t)base + off);
}
Run Code Online (Sandbox Code Playgroud)

这也可能会起作用,但请注意,intptr_t不需要存在,据我所知,算术intptr_t不需要产生正确的结果(例如我记得有些CPU有能力处理非字节对齐的地址,这会建议在数组中intptr_t每个步骤增加8 char.

看起来标准中有遗忘的东西(或者我错过的东西).

And*_*nle 3

根据C 标准7.19 通用定义<stddef.h>第 3 段offsetof()定义为:

\n\n
\n

宏是

\n\n
NULL\n
Run Code Online (Sandbox Code Playgroud)\n\n

它扩展为实现定义的空指针常量;和

\n\n
offsetof(*type*, *member-designator*)\n
Run Code Online (Sandbox Code Playgroud)\n\n

它扩展为具有 type\n 的整型常量表达式 size_t,其是以字节为单位的偏移量,从其结构的开头(由type指定)到\n 结构成员(由member-designator指定) 。

\n
\n\n

因此,offsetoff()返回以字节为单位的偏移量。

\n\n

6.2.6.1总则第 4 段规定:

\n\n
\n

存储在任何其他对象类型的非位字段对象中的值由\n n \xc3\x97 CHAR_BIT位组成,其中n是该类型对象的大小(以字节为单位)。

\n
\n\n

由于CHAR_BIT被定义为 a 中的位数char,因此 achar是一个字节

\n\n

因此,根据标准,这是正确的:

\n\n
int getint(struct A* base, size_t off) {\n    return *(int*)((char*)base + off); \n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

它转换base为 a并向地址char *添加字节。off如果off是 的结果,则结果地址是所指向offsetof(A, x);的地址。xstructure Abase

\n\n

你的第二个例子:

\n\n
int getint(struct A* base, size_t off) {\n    return *(int*)((intptr_t)base + off);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

取决于有符号intptr_t值与无符号size_t值相加的结果。

\n

  • 引用的部分完全无关紧要。标准的相关部分是 6.5 中关于指针别名的部分,或者可能是关于指针算术的部分。我不明白第二个例子会如何失败。`intptr_t` 是无符号整数类型,而不是指针类型。它不执行任何指针算术,因此您的假设是不正确的。 (4认同)