4

考虑一个具有两个整数类型成员的结构。我想通过地址获取两个成员。我可以成功获得第一个,但第二个我得到了错误的值。我相信这是垃圾价值。这是我的代码:

#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

有人可以解释我哪里出错了吗?

4

5 回答 5

7

按照 C 标准,第一个成员的偏移量必须始终为零;这就是为什么你的第一个演员有效。然而,由于填充,第二个成员的偏移量可能不一定等于结构的第一个成员的大小。

此外,向指针添加数字不会将字节数添加到地址:相反,添加了所指向事物的大小。因此,当您添加sizeof(int)到时&fsizeof(int)*sizeof(foo_t)会添加。

offsetof如果你想自己做数学,你可以使用运算符,像这样

int b = *((int*)(((char*)&f)+offsetof(foo_t, b)));

这样做的原因是它sizeof(char)始终是一个,正如 C 标准所要求的那样。

当然,您可以使用&f.b来避免手动进行数学运算。

于 2012-12-31T03:12:54.623 回答
2

你的问题是&f + sizeof(int)。如果A是一个指针,并且B是一个整数,那么A + B在 C 中并不意味着AB字节。相反,它表示AB元素,其中元素的大小由 的指针类型定义A。因此,如果sizeof(int)在您的体系结构上为 4,则&f + sizeof(int)表示“将 4 个foo_ts 放入&f,或 4 * 8 = 32 个字节放入&f”。

试试((char *)&f) + sizeof(int)吧。

或者,当然,&f.a而是&f.b非常简单。后者不仅会为您提供方便int的指示并让您摆脱所有这些强制转换,而且还可以定义明确且易于理解。:)

于 2012-12-31T03:13:30.867 回答
2

该表达式&f + sizeof(int)将一个数字添加到一个类型的指针foo_t*。指针算术始终假定指针指向数组的元素,并且该数字被视为元素的计数。

因此,如果sizeof(int)是 4,则指向过去的&f + sizeof(int)四个结构,或之后的字节。foo_tf4*sizeof(foo_t)&f

如果你必须使用字节数,这样的事情可能会起作用:

int b = *(int*)((char*)(&f) + sizeof(int));

...假设成员ab.

但是有什么理由你不只是得到值f.b或指针&f.b吗?

于 2012-12-31T03:14:06.440 回答
1

你可以做&f.b,并跳过实际的指针数学。

以下是我将如何更改您的int b线路:

int b = (int)(*(((int*)(&(f.b)))));

顺便说一句,当我按原样运行您的程序时,我得到2 ..0了输出。

于 2012-12-31T03:12:43.607 回答
1

这有效:

  int b = ((int)(*(int*)((int)&f + sizeof(int))));

您将 &f 解释为指针,当您向其添加 4(int 大小)时,它将其解释为添加 4 个指针,即 16 或 32 字节,具体取决于 32 与 64 拱。如果您将指针转换为 int ,它将正确添加 4 个字节。

这是对正在发生的事情的解释。我不确定你在做什么,但你肯定不应该那样做。这会让你在对齐等方面遇到麻烦。找出结构元素偏移的安全方法是:

  printf("%d\n", &(((foo_t *)NULL)->b));
于 2012-12-31T03:13:06.557 回答