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

Type casting struct to integer and vice versa in C++

所以,我看过这个线程 Type casting struct to integer c++ 关于如何在整数和结构(位域)之间进行转换,毫无疑问,编写适当的转换函数或重载相关的转换运算符是任何方法涉及操作系统的情况。 但是,当为只有一个闪存映像 运行 的小型嵌入式系统编写固件时,情况可能会有所不同,因为安全性并不是那么重要,而性能才是。 因为每次编译我的代码时我都可以测试代码是否正常工作(意味着位域的位按照我期望的方式排列),所以这里的答案可能不同。

所以,我的问题是,是否有 'proper' 方式在位域和无符号整数之间转换,在 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 以来未定义的行为。这些语言更改引入了严格的别名规则(它们允许编译器推断数据只能通过兼容类型的指针访问)以实现更好的优化。实际上,编译器不需要保持访问之间的顺序(或者根本不需要进行非类型访问)。对于大多数情况,这似乎不会出现 [直接] 问题,但是当使用更高的优化设置时(对于 gcc,即 -O,其中包括 -fstrict-aliasing),这将成为一个问题。 有关示例,请参阅 https://blog.regehr.org/archives/959

2) 使用联合进行类型双关似乎也涉及 C++ 而非 C 中的未定义行为(参见 ), however GCC (and probably others) does explicitly allow it: (See https://gcc.gnu.org/bugs/#nonbugs)。

3) 在 C++ 中进行类型双关的唯一真正可靠的方法似乎是使用 memcpy 将数据复制到新位置并执行任何要完成的操作,然后使用另一个 memcpy 到 return变化。我确实在 SO 的某个地方读到过,GCC(或者可能是大多数编译器)应该能够将 memcpy 优化为寄存器大小数据类型的单纯寄存器副本,但我再也找不到它了。

因此,如果您可以确定代码是由支持通过联合进行类型双关的编译器编译的,那么在这里最好的做法可能是使用联合。对于其他情况,需要进一步调查编译器如何处理更大的数据结构和 memcpy,如果这真的涉及来回复制,最好坚持按位运算。

union {
    struct {
        int part1: 10;
        int part2: 6;
        int part3: 16;
    } parts;
    int whole;
} word;

那就用word.whole.

我遇到了同样的问题。我猜今天这不是很相关。但我是这样解决的:

#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;
}

这现在适合一个整数,并且可以由标准整数赋值。但是我不知道这个解决方案的便携性如何。然后输出为:

size: 4
Values ( x, y, z ) = 0 0 -1
As integer: -1048576