代码之家  ›  专栏  ›  技术社区  ›  Matěj Zábský

直接访问结构成员

  •  1
  • Matěj Zábský  · 技术社区  · 17 年前

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

    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->代码中的成员构造?

    8 回复  |  直到 17 年前
        1
  •  13
  •   JaredPar    17 年前

    看起来你在问两个问题

    治疗&作为一个3长度的整数数组进行测试?

    可能最好避免这种情况。这可能是C++标准中定义的一个动作,但即使是,也不可能每个人都能理解你在这里做的事情。我认为,如果您阅读该标准,则不支持此操作,因为可能会填充结构,但我不确定。

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

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

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

    int* pointerToC = &(someTest->c);
    
        2
  •  5
  •   anon anon    17 年前

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

        3
  •  4
  •   Community Mohan Dere    9 年前

    增加 JaredPar's answer 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
    }
    
        4
  •  2
  •   dirkgently    17 年前

    您可能正在寻找 offsetof stddef.h 让它工作。

        5
  •  1
  •   Max    17 年前

        6
  •  0
  •   bayda    17 年前

    对create functor使用set方法和boost::bind,这将更改此变量。

        7
  •  0
  •   Tom    17 年前

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

    考虑一下这个小修改:

    test* t = new test;
    int* ptr = (int*) t;
    
    t->c = 13;
    ptr[2] = 15;
    cout << t->c;
    

    13 15 ,这取决于编译器使用的操作顺序。

        8
  •  0
  •   j_random_hacker    17 年前

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

    指向POD结构对象的指针, 使用 重新解释_cast,指向它的 初始成员(或如果该成员是 位字段,然后输入到 因此,可能存在未命名的问题 POD结构对象中的填充, 但不是在它的开始,如果必要的话 以实现适当的对齐。]

    private: , protected: public: )在他们之间。所以,治疗你的大脑的最初部分 struct test 因为3个整数的数组在技术上是未定义的行为。