【问题标题】:Accessing struct member by address通过地址访问结构成员
【发布时间】:2012-12-31 03:05:28
【问题描述】:

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

#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

谁能解释我哪里出错了?

【问题讨论】:

  • 你为什么不像int a = f.a;那样在int a的声明中这样做?您正在“访问结构”,就好像它是分配的内存一样,但显然您不是!
  • @t0mm13b: 目的学习..

标签: c pointers struct


【解决方案1】:

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

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

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

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

这样做的原因是sizeof(char)总是为一,这是 C 标准所要求的。

当然,您可以使用&amp;f.b 来避免手动计算。

【讨论】:

  • offsetof 不是非标准的 GCC 扩展吗?
  • @Dolda2000 不,那是 ANSI C:见第 7.17.3 节 here;
  • 你确定吗?即使是现在,当我查看 GCC 手册时,它也会在其 C 扩展名下列出 offsetof。当然,它可能后来在标准中定义了。
  • @Dolda2000 根据我之前评论中的链接,这至少从 2005 年开始就成为标准,但我想我在九十年代后期跨平台使用它。不过,它本来可以作为 gcc 扩展开始的。
【解决方案2】:

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

改用((char *)&amp;f) + sizeof(int)。

或者,当然,&amp;f.a 和 &amp;f.b 很简单。后者不仅会给你方便的int 指针,让你摆脱所有这些强制转换,而且定义明确且易于理解。 :)

【讨论】:

    【解决方案3】:

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

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

    如果您必须使用字节计数,这样的方法可能会起作用:

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

    ...假设成员 a 和 b 之间没有填充。

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

    【讨论】:

      【解决方案4】:

      这行得通:

        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));
      

      【讨论】:

      • ((int)&amp;f + sizeof(int)) 将对带有sizeof(int *) &gt; sizeof(int) 的系统造成严重破坏。 (int*)&amp;f + 1 或 (uintptr_t)&amp;f + sizeof(int) 将起作用,除非编译器在成员之间添加填充。
      【解决方案5】:

      您可以使用&amp;f.b,并跳过实际的指针数学运算。

      我将如何更改您的 int b 行:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-12-17
        • 1970-01-01
        • 2021-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多