我认为在C中不可能,但要求验证这一点。是否可以在没有这种类型的实变量的结构成员之间进行算术运算?例如:
typedef struct _s1
{
int a;
int b;
int c;
} T1;
我希望看到“c”成员与结构开始的偏移量。如果我有变量很容易:
T1 str;
int dist = (int)&str.c - (int)&str;
但是我的结构太大而且RAM中没有成员(仅在EEPROM中)。我想做一些地址计算,但不想定义RAM成员。我可以使用结构指针而不是结构变量(它只需要4个字节)来完成工作,但这个案例对我来说很有意思。
答案 0 :(得分:57)
使用offsetof,您可以在成员之间进行计算,而无需获取该类型的变量。您只需要类型本身和成员的名称。
注意为什么简单计算可能无法解决:数据对齐。您不知道编译器将在您的结构中抛出的填充量,如果更改结构,这可能会导致非常微妙的错误或使看似正确的计算错误。
答案 1 :(得分:25)
首先,您将个别地址转换为int
。我认为这不是一个好主意。保证int
的大小至少为 2 字节或更大,地址/指针通常为4或8字节。将这些转换为int
并不恰到好处。如果我将它们转换为任何东西,我可能会将unsigned long
用于32位系统,将unsigned long long
用于64位。我会用后者来保证安全
也就是说,我根本不会转发地址,只使用offsetof
宏。
将#include <stddef.h>
添加到您的文件中,并使用offsetof
宏,将偏移值转换为size_t
类型,而不是int
,请注意。它只使用0作为结构的内存地址,然后返回给定成员的地址,给出实际的偏移量:
size_t offset = offsetoff(T1, c);
//struct, member
正如扎克在评论中指出的那样,答案的下一部分有点无关紧要,但对于它所包含的链接,为了完整起见,我将把它留在这里 - 因为offsetof
是必需的所有实现:
如果由于某种原因没有stddef.h,那么自己定义一下宏(应该是这样,因为offsetof
已经成为标准的一部分了一段时间:C89及以上),就像这样:
#ifndef offsetof
#define offsetof(s, m) ((size_t)&(((s *) 0)->m))
#endif
应该这样做,但要小心:这种实现可能会导致未定义的行为。 How and why is explained here
我从the stddef.h source I found here获取了上面的offsetof
定义,因此您可以下载该文件并使用它,而不是在您自己的文件中定义宏,但请记住{{1}你使用不是100%可靠。
无论如何,现在已经足够了,谷歌有更多信息,但这里有几个链接:
答案 2 :(得分:16)
我知道这超出了你的要求,但是在Linux内核代码offsetof
宏中有一个有用的container_of
用法。 container_of
可以返回父结构的地址,给定指向其中一个成员的指针:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
您可以使用例如:
// pointer_to_c points to a member of the struct, c in this case
// and you want to get the address of the container
T1 *container;
container = container_of(pointer_to_c, T1, c);
答案 3 :(得分:12)
答案 4 :(得分:10)
答案 5 :(得分:8)
标题stddef.h
中有一个宏; offsetof
。您可以在结构上使用它,如下所示:
int dist = (int)offsetof(T1, c);