下面的程序对bit-fields的打包、类型双关和对象表示进行了假设。换句话说,它在可移植性方面没有任何伪装。它仍然具有being fast的优势。这个程序是否可以说是正确的,因为它需要一个受支持的编译器和一个具有正确endity的平台?
#include <cassert>
#include <cstdint>
union Data {
uint8_t raw[2];
struct __attribute__((packed)) {
unsigned int field1: 3, field2: 3, field3: 1, field4: 2;
unsigned int field5: 7;
} interpreted;
};
int main() {
static_assert(sizeof(Data) == 2, "Struct size incorrect");
static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, "Only little-endian platform support is currently implemented");
static_assert(
#if defined(__GNUC__) || defined(__clang__)
true,
#else
false,
#endif
"Compiler is neither GCC nor Clang"
);
Data d{.raw{0x69, 0x01}};
/**
*
* 0x69 = 0b0110 1001, 0x01 = 0b0000 0001
* On a little endian platform, each byte will be laid out in memory in reverse order, that is
* [1001 0110, 1000 0000].
* The GCC and clang compilers lay out the struct members in the order they are defined, and each of the values will be interpreted in the reverse order (little-endian), so
* field1: 100 = 0b001
* field2: 101 = 0b101
* field3: 1 = 0b1
* field4: 01 = 0b10
* field5: 0000000 = 0
*
* Therefore, the following assertions will hold if the preceding assertions were satisfied.
*/
assert(d.interpreted.field1 == 1);
assert(d.interpreted.field2 == 5);
assert(d.interpreted.field3 == 1);
assert(d.interpreted.field4 == 2);
assert(d.interpreted.field5 == 0);
}
1条答案
按热度按时间0ve6wy6x1#
你的问题让我考虑如何使用Ada编程语言来表达这一点。下面的示例将按照您希望的方式工作。
我首先为位字段中需要的每个字段类型定义数据类型。因此,类型bit_3被定义为3比特整数,bit_1被定义为1比特整数,bit_2被定义为2比特整数,并且bit_7被定义为7比特整数。
然后,我创建了一个名为bit_fields的记录类型,指定了您在示例中指定的字段。记录定义子句之后的记录表示子句指定记录的精确位布局,位号从字节0的开头开始。
然后,我创建了一个名为unint_8的1字节整数类型,大小为8位。我为unint_8示例化了一个通用I/O包,以便可以以二进制形式输出该类型的值。我创建了一个名为two_bytes的数组类型,其中包含两个unint_8元素。
Ada没有工会本身。我通过创建一个名为foo的two_bytes示例,后面跟着一个名为bar的bit_fields示例,并将bar的地址设置为与变量foo相同的地址,实现了相同的效果。
我将值hex 69和1分配给foo的两个元素,并以二进制打印foo,然后以十进制打印bar的每个字段。
这个程序的输出是: