在结构中访问联合

时间:2019-03-02 23:15:21

标签: c++ loops c++11 struct unions

考虑以下代码:

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: %x\n", *ptr, ptr);
ptr++;
printf("val: %i addr: %x\n", *ptr, ptr);

是否有更合适的方法可以从示例finalstruct内部的并集中访问值?使用上面示例中的代码,我可以遍历“ finalstruct”中的所有并集,并获得所需的int,但是还有其他方法可以做到这一点吗?

假设所有结构的数据大小都小于或等于union内部变量的大小-结构将被视为位字段,并且数据将通过union变量读取。

这将仅用于一种类型的处理器,使用一个编译器(gcc)进行编译,并且所有结构和联合的大小都将相同(当然,除finalstruct外)。我要实现的目标是能够通过使用struct(test1str,test2str)轻松更改不同的位,而对于阅读,我只需要知道这些位将产生的最终值是什么,为此我将使用并集(test1uni,test2uni)。通过将这些联合打包在struct(finalstruct)中,我可以轻松处理所有数据。

2 个答案:

答案 0 :(得分:1)

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: %p\n", ptr->get(), (void*)&ptr->get());
ptr++;
printf("val: %i addr: %p\n", ptr->get(), (void*)&ptr->get());

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

答案 1 :(得分:-1)

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

如果您确定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: %x\n", ptr[i], &ptr[i]);

但是正如注释中提到的,将结构强制转换为int可能违反严格的别名,并且在C ++中不再明确允许使用union成员进行“类型操纵”(相对于明确不允许的情况)。因此,这属于不确定行为的领域,因此您需要:

  1. 基于严格的别名禁用优化。例如。将-fno-strict-aliasing传递到GCC 3.4.1及更高版本。不过仍然存在类型问题。
  2. 检查程序集,以确保编译器正在执行所需的操作。
  3. 更改为C。

还要注意其他陷阱:int必须是单词的倍数,finstr必须与单词边界对齐,编译器/平台必须遵循约定。因此,如果没有更多的严格要求,我当然不会考虑这种便携式产品。