考虑一个包含两个整数类型成员的结构。我希望通过地址获得两位成员。我可以成功获得第一个,但是我的第二个错误。我相信这是垃圾价值。这是我的代码:
#include <stdio.h>
typedef struct { int a; int b; } foo_t;
int main(int argc, char **argv)
{
foo_t f;
f.a = 2;
f.b = 4;
int a = ((int)(*(int*) &f));
int b = ((int)(*(((int*)(&f + sizeof(int))))));
printf("%d ..%d\n", a, b);
return 0;
}
我得到了:
2 ..1
有人可以解释我出错的地方吗?
答案 0 :(得分:7)
第一个成员的偏移量必须始终为C标准的零;这就是你的第一次演员工作的原因。但是,由于填充,第二个成员的偏移量可能不一定等于结构的第一个成员的大小。
此外,向指针添加数字不会向地址添加字节数:而是添加指向的事物的大小。因此,当您向sizeof(int)
添加&f
时,会添加sizeof(int)*sizeof(foo_t)
。
如果您想自己进行数学运算,可以使用offsetof
运算符,例如
int b = *((int*)(((char*)&f)+offsetof(foo_t, b)));
这有效的原因是sizeof(char)
总是一个,符合C标准的要求。
当然,您可以使用&f.b
来避免手动进行数学运算。
答案 1 :(得分:2)
您的问题是&f + sizeof(int)
。如果A
是指针,并且B
是整数,那么{C}中的A + B
不会表示A
加B
个字节。相反,它意味着A
加B
个元素,其中元素的大小由A
的指针类型定义。因此,如果您的体系结构中sizeof(int)
为4,则&f + sizeof(int)
表示“foo_t
四个&f
,或&f
中的4 * 8 = 32个字节”
请尝试((char *)&f) + sizeof(int)
。
或者,当然,&f.a
和&f.b
相反,非常简单。后者不仅会给你提供方便的int
指针,而且会让你免除所有这些演员阵容,同时也能明确定义和理解。 :)
答案 2 :(得分:2)
表达式&f + sizeof(int)
为类型为foo_t*
的指针添加数字。指针算术始终假定指针指向数组的元素,并将该数字视为元素计数。
因此,如果sizeof(int)
为4,则&f + sizeof(int)
指向foo_t
之后的四个f
结构,或4*sizeof(foo_t)
之后的&f
字节。
如果必须使用字节计数,这样的事情可能会起作用:
int b = *(int*)((char*)(&f) + sizeof(int));
...假设成员a
和b
之间没有填充。
但是,您是否有任何理由不仅获得值f.b
或指针&f.b
?
答案 3 :(得分:1)
您可以执行&f.b
,并跳过实际的指针数学。
以下是我如何更改int b
行:
int b = (int)(*(((int*)(&(f.b)))));
顺便说一句,当我按原样运行你的程序时,我得到2 ..0
作为输出。
答案 4 :(得分:1)
这有效:
int b = ((int)(*(int*)((int)&f + sizeof(int))));
您正在将&amp; f解释为指针,当您向其添加4(int的大小)时,它会将其解释为添加4个指针,这些指针是16或32个字节,具体取决于32对64拱。如果将指针强制转换为int,则会正确地向其添加4个字节。
这是对正在发生的事情的解释。我不确定你在做什么,但你肯定不应该这样做。这可能会使您在对齐等方面遇到麻烦。找出struct元素偏移量的安全方法是:
printf("%d\n", &(((foo_t *)NULL)->b));