考虑以下代码:
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)中,我可以轻松处理所有数据。
答案 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成员进行“类型操纵”(相对于明确不允许的情况)。因此,这属于不确定行为的领域,因此您需要:
-fno-strict-aliasing
传递到GCC 3.4.1及更高版本。不过仍然存在类型问题。还要注意其他陷阱:int
必须是单词的倍数,finstr
必须与单词边界对齐,编译器/平台必须遵循约定。因此,如果没有更多的严格要求,我当然不会考虑这种便携式产品。