在C ++中将类型转换为整数,反之亦然

时间:2015-07-27 17:18:56

标签: c++ optimization struct casting bit-fields

所以,我已经看到这个线程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,如果这真的涉及来回复制,可能坚持按位操作是最好的主意。

2 个答案:

答案 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