访问结构中的工会

Accessing unions in struct

本文关键字:结构 访问      更新时间:2023-10-16

请考虑以下代码:

struct test1str
{
    int testintstr : 2;
    int testintstr2 : 1;
};
struct test2str
{
    int testintstr : 2;
    int testintstr2 : 1;
};
union test1uni
{
    int testint1;
    test1str str1;
};
union test2uni
{
    int testint2;
    test2str str2;
};
struct finalstruct
{
    test1uni union1;
    test2uni union2;
} finstr;
int* ptr = &finstr.union1.testint1;
finstr.union1.testint1 = 2;
finstr.union2.testint2 = 4;
cout << &finstr.union1 << endl;
cout << &finstr.union2 << endl;
printf("val: %i addr: %xn", *ptr, ptr);
ptr++;
printf("val: %i addr: %xn", *ptr, ptr);

是否有更合适的方法访问示例内部的工会的价值?使用上面示例中的代码,我可以通过" interalsstruct"中的所有工会迭代,并获得所需的int,但是还有其他方法可以做到吗?

假设所有结构的数据大小都将较小或等于联合内部变量的大小 - 结构将被视为比特场,并且数据将通过联合变量读取。

这将仅在一种类型的处理器上使用,该处理器与一个组合商(GCC)一起编译,所有结构和工会的尺寸都将相同(当然是决赛除外)。我要实现的目标是能够通过使用struct(test1str,test2str)轻松更改不同的位,而为了阅读,我只需要知道这些位将产生的最终价值 - 因为我将使用Union(test1uni,test2uni)。通过将这些工会包装在struct(Jinalstruct)中,我可以轻松处理所有数据。

ptr++

ptr并不指向数组的元素,因此,在将其递增后,它不再有效 - 即使该地址中碰巧有另一个对象。当您间接浏览它时,该程序的行为是不确定的。

您真正需要迭代班级成员的语言功能称为"反射"。C 对反射的支持非常有限。您可以在数组中存储对成员的引用,并迭代数组。请注意,由于我们不能有参考数组,因此我们需要包装它们,并且在printf的情况下,明确将包装器转换回:

std::array members {
    std::ref(finstr.union1.testint1),
    std::ref(finstr.union2.testint2),
};
auto ptr = std::begin(members);
printf("val: %i addr: %pn", ptr->get(), (void*)&ptr->get());
ptr++;
printf("val: %i addr: %pn", ptr->get(), (void*)&ptr->get());

P.S。我自由修复了printf呼叫。%x对于指针是错误的。

我认为我不太了解您要实现的目标,但是...

如果您确定sizeof(test1uni) == sizeof(test2uni) == sizeof(int)并且结构中没有其他其他内容,那么您可以将finalstruct本身视为int S的数组:

int *ptr = (int*)&finstr;
for(int i=0; i<sizeof(finstr)/sizeof(int); i++)
    printf("val: %i addr: %xn", ptr[i], &ptr[i]);

但是,正如评论中提出的那样,将结构施放给INT可能违反了严格的混叠,并且不再在C 中明确允许使用工会成员进行"打字"(而不是明确不允许)。因此,这是在不确定行为的领域中,因此您需要:

  1. 基于严格的混叠来禁用优化。例如。将-fno-strict-aliasing传递到GCC 3.4.1及以上。
  2. 仍然有易货类型的问题。
  3. 检查组件以确保编译器正在执行您想要的操作。
  4. 更改为c。

还要注意其他陷阱:int必须是单词的倍数,finstr必须与单词边界保持一致,编译器/平台必须遵循约定。因此,我当然不会考虑这个便携式,而没有更严格的情况。