所以,我已经看到这个线程Type casting struct to integer c++关于如何在整数和结构(位域)之间进行转换,毫无疑问,编写适当的转换函数或重载相关的转换运算符是任何情况下的方法。有涉及的操作系统。 但是,当为只运行一个闪存映像的小型嵌入式系统编写固件时,情况可能会有所不同,因为在性能方面,安全性并不是很重要。 由于我可以测试代码是否正常工作(意味着位域的位按照我期望的方式排列),每次编译代码时,答案可能会有所不同。
所以,我的问题是,是否有一种'正确'的方法在bitfield和unsigned int之间进行转换,这种方式在g ++中编译为无操作(当编译器知道位在内存中正确排列时,可能会移位优化)。
这是原始问题的摘录:
struct {
int part1 : 10;
int part2 : 6;
int part3 : 16;
} word;
然后我可以将part2设置为等于请求的任何值,并将其他部分设置为0.
word.part1 = 0;
word.part2 = 9;
word.part3 = 0;
我现在想要获取该结构,并将其转换为单个32位整数。我确实通过强制转换来进行编译,但它似乎不是一种非常优雅或安全的数据转换方式。
int x = *reinterpret_cast<int*>(&word);
编辑: 现在,很久以后,我学到了一些东西:
1)通过指针转换类型惩罚(改变数据的解释)是自C99和C ++ 98以来的未定义行为。这些语言更改引入了严格的别名规则(它们允许编译器推断数据仅通过兼容类型的指针访问)以允许更好的优化。实际上,编译器不需要保持访问之间的顺序(或完全执行off-type访问)。对于大多数情况,这似乎不会出现[立即]问题,但是当使用更高的优化设置时(对于包含-fstrict-aliasing的-O的gcc),这将成为一个问题。 有关示例,请参阅https://blog.regehr.org/archives/959
2)使用联合进行类型惩罚似乎也涉及C ++中的未定义行为,但不包括C(参见https://stackoverflow.com/a/25672839/4360539),但是GCC(可能还有其他人)明确允许它:(参见https://gcc.gnu.org/bugs/#nonbugs)
3)在C ++中进行类型惩罚的唯一真正可靠的方法似乎是使用memcpy将数据复制到新位置并执行任何要执行的操作,然后使用另一个memcpy返回更改。我确实在SO上读过,GCC(或者大多数编译器可能)应该能够将memcpy优化为寄存器大小的数据类型的寄存器副本,但我再也找不到了。
因此,如果您可以确定代码是由支持通过union进行类型惩罚的编译器编译的,那么这里最好的做法就是使用union。对于其他情况,需要进一步调查编译器如何处理更大的数据结构和memcpy,如果这真的涉及来回复制,可能坚持按位操作是最好的主意。
答案 0 :(得分:3)
union {
struct {
int part1: 10;
int part2: 6;
int part3: 16;
} parts;
int whole;
} word;
然后使用word.whole
。
答案 1 :(得分:0)
我遇到了同样的问题。我猜这今天不太相关。但这就是我解决它的方式:
#include <iostream>
struct PACKED{
int x:10;
int y:10;
int z:12;
PACKED operator=(int num )
{
*( int* )this = num;
return *this;
}
operator int()
{
int *x;
x = (int*)this;
return *x;
}
} __attribute__((packed));
int main(void) {
std::cout << "size: " << sizeof(PACKED) << std::endl;
PACKED bf;
bf = 0xFFF00000;
std::cout << "Values ( x, y, z ) = " << bf.x << " " << bf.y << " " << bf.z << std::endl;
int testint;
testint = bf;
std::cout << "As integer: " << testint << std::endl;
return 0;
}
现在适用于int,可以通过标准int分配。但是我不知道这个解决方案有多便携。然后输出:
size: 4 Values ( x, y, z ) = 0 0 -1 As integer: -1048576