简体   繁体   English

直接访问结构成员

[英]Accessing struct members directly

I have a testing struct definition as follows:我有一个测试结构定义如下:

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

And somewhere I use it this way:在某处我以这种方式使用它:

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

This works correctly on my Windows - it prints 15 as expected, but is it safe?这在我的 Windows 上正常工作 - 它按预期打印 15,但它安全吗? Can I be really sure the variable is on the spot in memory I want it to be - expecially in case of such combined structs (for example f is on my compiler the fifth word, but it is a sixth variable)?我真的可以确定变量在 memory 中吗?

If not, is there any other way to manipulate struct members directly without actually having struct->member construct in the code?如果没有,是否有任何其他方法可以直接操作 struct 成员,而无需在代码中实际使用 struct->member 构造?

It looks like you are asking two questions看起来你在问两个问题

Is it safe to treat &test as a 3 length int arrray?将 &test 视为 3 长度的 int 数组是否安全?

It's probably best to avoid this.最好避免这种情况。 This may be a defined action in the C++ standard but even if it is, it's unlikely that everyone you work with will understand what you are doing here.这可能是 C++ 标准中定义的操作,但即使是这样,与您一起工作的每个人都不太可能理解您在此做什么。 I believe this is not supported if you read the standard because of the potential to pad structs but I am not sure.我相信如果您阅读标准,因为可能填充结构,这不受支持,但我不确定。

Is there a better way to access a member without it's name?有没有更好的方法来访问没有名字的成员?

Yes.是的。 Try using the offsetof macro/operator.尝试使用offsetof宏/运算符。 This will provide the memory offset of a particular member within a structure and will allow you to correctly position a point to that member.这将提供结构中特定成员的 memory 偏移量,并允许您正确 position 指向该成员。

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

Another way though would be to just take the address of c directly另一种方法是直接获取 c 的地址

int* pointerToC = &(someTest->c);

No you can't be sure.不,你不能确定。 The compiler is free to introduce padding between structure members.编译器可以自由地在结构成员之间引入填充。

To add to JaredPar's answer , another option in C++ only (not in plain C) is to create a pointer-to-member object:要添加到JaredPar 的答案,仅 C++ 中的另一个选项(不在纯 C 中)是创建指向成员 object 的指针:

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
}

You are probably looking for the offsetof macro.您可能正在寻找offsetof宏。 This will get you the byte offset of the member.这将为您提供成员的字节偏移量。 You can then manipulate the member at that offset.然后,您可以在该偏移处操作成员。 Note though, this macro is implementation specific.但请注意,此宏是特定于实现的。 Include stddef.h to get it to work.包括stddef.h以使其工作。

It's probably not safe and is 100% un-readable;它可能不安全并且 100% 不可读; thus making that kind of code unacceptable in real life production code.从而使这种代码在现实生活中的生产代码中不可接受。

use set methods and boost::bind for create functor which will change this variable.使用 set 方法和 boost::bind 创建函子,这将改变这个变量。

Aside from padding/alignment issues other answers have brought up, your code violates strict aliasing rules, which means it may break for optimized builds (not sure how MSVC does this, but GCC -O3 will break on this type of behavior).除了填充/对齐问题之外,其他答案已经提出,您的代码违反了严格的别名规则,这意味着它可能会因优化构建而中断(不确定 MSVC 是如何做到这一点的,但 GCC -O3会在这种类型的行为上中断)。 Essentially, because test *t and int *ptr are of different types, the compiler may assume they point to different parts of memory, and it may reorder operations.本质上,因为test *tint *ptr是不同的类型,编译器可能会假设它们指向 memory 的不同部分,并且它可能会重新排序操作。

Consider this minor modification:考虑这个小修改:

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

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

The output at the end could be either 13 or 15 , depending on the order of operations the compiler uses.最后的 output 可以是1315 ,具体取决于编译器使用的操作顺序。

According to paragraph 9.2.17 of the standard, it is in fact legal to cast a pointer-to-struct to a pointer to its first member, providing the struct is POD :根据标准的第 9.2.17 段,实际上将指向结构的指针转换为指向其第一个成员的指针是合法的,前提是该结构是POD

A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.指向 POD 结构 object 的指针,使用 reinterpret_cast 适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。 [Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment. [注意:因此,在 POD 结构 object 中可能存在未命名的填充,但不是在其开头,这是实现适当 alignment 所必需的。 ] ]

However, the standard makes no guarantees about the layout of structs -- even POD structs -- other than that the address of a later member will be greater than the address of an earlier member, provided there are no access specifiers ( private: , protected: or public: ) between them.但是,该标准不保证结构的布局——即使是 POD 结构——除了后面成员的地址将大于前面成员的地址,前提是没有访问说明符( private:protected:public: ) 他们之间。 So, treating the initial part of your struct test as an array of 3 integers is technically undefined behaviour.因此,将struct test的初始部分视为 3 个整数的数组在技术上是未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM