2

我有一个测试结构定义如下:

struct test{
    int a, b, c;
    bool d, e;
    int f;
    long g, h;
};

在某处我以这种方式使用它:

test* t = new test;   // create the testing struct
int* ptr = (int*) t;
ptr[2] = 15;          // directly manipulate the third word
cout << t->c;         // look if it really affected the third integer

这在我的 Windows 上正常工作 - 它按预期打印 15,但它安全吗?我真的可以确定变量在我想要的内存中的位置吗?特别是在这种组合结构的情况下(例如 f 在我的编译器上是第五个单词,但它是第六个变量)?

如果没有,是否有任何其他方法可以直接操作 struct 成员,而无需在代码中实际使用 struct->member 构造?

4

8 回答 8

13

看起来你在问两个问题

将 &test 视为 3 长度的 int 数组是否安全?

最好避免这种情况。这可能是 C++ 标准中定义的操作,但即使是这样,与您一起工作的每个人都不太可能理解您在这里所做的事情。我相信如果您阅读标准,因为可能填充结构,这不受支持,但我不确定。

有没有更好的方法来访问没有名字的成员?

是的。尝试使用offsetof宏/运算符。这将提供结构中特定成员的内存偏移量,并允许您正确定位指向该成员的点。

size_t offset = offsetof(mystruct,c);
int* pointerToC = (int*)((char*)&someTest + offset);

另一种方法是直接获取 c 的地址

int* pointerToC = &(someTest->c);
于 2009-03-08T15:08:52.733 回答
5

不,你不能确定。编译器可以自由地在结构成员之间引入填充。

于 2009-03-08T15:04:11.437 回答
4

要添加到JaredPar 的答案,仅在 C++ 中(不是在纯 C 中)的另一个选项是创建一个指向成员对象的指针:

struct test
{
  int a, b, c;
  bool d, e;
  int f;
  long g, h;
};

int main(void)
{
  test t1, t2;

  int test::*p;  // declare p as pointing to an int member of test
  p = &test::c;  // p now points to 'c', but it's not associating with an object
  t1->*p = 3;    // sets t1.c to 3
  t2->*p = 4;    // sets t2.c to 4

  p = &test::f;
  t1->*p = 5;    // sets t1.f to 5
  t2->*p = 6;    // sets t2.f to 6
}
于 2009-03-08T15:52:07.077 回答
2

您可能正在寻找offsetof宏。这将为您提供成员的字节偏移量。然后,您可以在该偏移处操作成员。但请注意,此宏是特定于实现的。包括stddef.h让它工作。

于 2009-03-08T15:12:03.663 回答
1

它可能不安全并且 100% 不可读;从而使这种代码在现实生活中的生产代码中不可接受。

于 2009-03-08T15:09:19.537 回答
0

使用 set 方法和 boost::bind 创建函子,这将改变这个变量。

于 2009-03-08T15:34:08.213 回答
0

除了填充/对齐问题之外,其他答案已经提出,您的代码违反了严格的别名规则,这意味着它可能会因优化构建而中断(不确定 MSVC 是如何做到这一点的,但 GCC-O3会因这种行为而中断)。本质上,因为test *tint *ptr是不同的类型,编译器可能会假设它们指向内存的不同部分,并且它可能会重新排序操作。

考虑这个小修改:

test* t = new test;
int* ptr = (int*) t;

t->c = 13;
ptr[2] = 15;
cout << t->c;

最后的输出可能是1315,具体取决于编译器使用的操作顺序。

于 2009-03-08T16:18:00.523 回答
0

根据标准的第 9.2.17 段,实际上将指向结构的指针转换为指向其第一个成员的指针是合法的,前提是该结构是POD

使用 reinterpret_cast 适当转换的指向 POD 结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。[注意:因此,在 POD 结构对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的。]

但是,该标准不保证结构的布局——即使是 POD 结构——除了后面成员的地址将大于前面成员的地址,前提是之间没有访问说明符 ( private:,protected:public:)他们。因此,将您的初始部分struct test视为 3 个整数的数组在技术上是未定义的行为。

于 2009-03-10T17:03:28.463 回答