如何使用"offsetof"以一种标准的方式访问字段? [英] How do one use `offsetof` to access a field in a standard conforming way?

查看:160
本文介绍了如何使用"offsetof"以一种标准的方式访问字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

struct A {
    int x;
};

size_t xoff = offsetof(A, x);

如何给定指向struct A的指针,以一种标准的方式提取成员?当然,假设我们有正确的struct A*和正确的偏移量.一种尝试是做类似的事情:

int getint(struct A* base, size_t off) {
    return *(int*)((char*)base + off); 
}

这可能会起作用,但是请注意,例如,如果指针是同一数组(或末尾的一个)的指针,则似乎仅在标准中定义了指针算术,而不必如此.因此从技术上讲,该构造似乎依赖于不确定的行为.

另一种方法是

int getint(struct A* base, size_t off) {
    return *(int*)((uintptr_t)base + off);
}

也可能会起作用,但是请注意,不需要intptr_t存在,而且据我所知,intptr_t上的算术运算不需要产生正确的结果(例如,我记得某些CPU具有此功能处理非字节对齐的地址,这表明对于数组中的每个charintptr_t以8为步长递增.)

似乎标准中有一些遗忘的东西(或者我错过了的东西).

解决方案

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

宏是

NULL

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

offsetof(*type*, *member-designator*)

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

因此,offsetoff()返回一个以 bytes 个字节为单位的偏移量.

6.2.6.1常规,第4段指出:

存储在任何其他对象类型的非位字段对象中的值 包括 n × CHAR_BIT 位,其中 n 是该类型对象的大小,以字节为单位.

由于 CHAR_BIT 被定义为char中的位数,所以char是一个 byte .

因此,按照标准,这是正确的:

int getint(struct A* base, size_t off) {
    return *(int*)((char*)base + off); 
}

base转换为char *并将off字节添加到地址.如果offoffsetof(A, x);的结果,则结果地址是base指向的structure A中的x的地址.

您的第二个示例:

int getint(struct A* base, size_t off) {
    return *(int*)((intptr_t)base + off);
}

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

Let's suppose I have a struct and extract the offset to a member:

struct A {
    int x;
};

size_t xoff = offsetof(A, x);

how can I, given a pointer to struct A extract the member in a standard conforming way? Assuming of course that we have a correct struct A* and a correct offset. One attempt would be to do something like:

int getint(struct A* base, size_t off) {
    return *(int*)((char*)base + off); 
}

Which probably will work, but note for example that pointer arithmetics only seem to be defined in the standard if the pointers are pointers of the same array (or one past the end), this need not be the case. So technically that construct would seem to rely on undefined behaviour.

Another approach would be

int getint(struct A* base, size_t off) {
    return *(int*)((uintptr_t)base + off);
}

which also probably would work, but note that intptr_t is not required to exist and as far as I know arithmetics on intptr_t doesn't need to yield the correct result (for example I recall some CPU has the capability to handle non-byte aligned addresses which would suggest that intptr_t increases in steps of 8 for each char in an array).

It looks like there's something forgotten in the standard (or something I've missed).

解决方案

Per the C Standard, 7.19 Common definitions <stddef.h>, paragraph 3, offsetof() is defined as:

The macros are

NULL

which expands to an implementation-defined null pointer constant; and

offsetof(*type*, *member-designator*)

which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type).

So, offsetoff() returns an offset in bytes.

And 6.2.6.1 General, paragraph 4 states:

Values stored in non-bit-field objects of any other object type consist of n × CHAR_BIT bits, where n is the size of an object of that type, in bytes.

Since CHAR_BIT is defined as the number of bits in a char, a char is one byte.

So, this is correct, per the standard:

int getint(struct A* base, size_t off) {
    return *(int*)((char*)base + off); 
}

That converts base to a char * and adds off bytes to the address. If off is the result of offsetof(A, x);, the resulting address is the address of x within the structure A that base points to.

Your second example:

int getint(struct A* base, size_t off) {
    return *(int*)((intptr_t)base + off);
}

is dependent upon the result of the addition of the signed intptr_t value with the unsigned size_t value being unsigned.

这篇关于如何使用"offsetof"以一种标准的方式访问字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆