我使用运行mbedOS 5.9的ARM®Cortex™-M4F CPU遇到以下问题。
假设我具有二进制值10101000
,并且我还具有以下union / struct:
union InputWord_u
{
uint8_t all;
struct BitField_s
{
uint8_t start : 1; // D7
uint8_t select : 3; // D6, D5, D4
uint8_t payload : 4; // D3, D2, D1, D0
} bits;
};
我有一个简单的程序,可以访问我的单词并按以下方式分配值:
InputWord_u word;
word.bits.start = 0b1;
word.bits.select = 0b010;
word.bits.payload = 0b1000;
因此,word.all == 10101000
是uint8_t
。
如果我这样打印printf("%u", word.all);
,那么我会收到133
的值。
如果我再定义以下uint8_t
:
uint8_t value = 0b10101000;
并使用printf("%u", value);
打印,然后我收到值168
。
我希望两个值都等于168。
我很欣赏这很可能是我严重误解了Struct在内存中的表示方式。但是,有人可以解释到底发生了什么吗?
谢谢。
答案 0 :(得分:4)
该标准几乎不能保证位域的表示。
因此,
word.all == 10101000
您在这里遇到的问题是,您假设位字段是从最高有效位到最低有效位打包的。
但是,看来您的位字段是以相反的顺序存储的,实际上是word.all == 1000'010'1
。为了获得您期望的结果,您可以对位字段重新排序:
struct BitField_s
{
uint8_t payload : 4; // D3, D2, D1, D0
uint8_t select : 3; // D6, D5, D4
uint8_t start : 1; // D7
} bits;
但是请注意,位错不可移植:其他系统可能没有相同的顺序。
答案 1 :(得分:3)
问题是,您以相反的方式计算值,例如
(start << 7) | (select << 4) | payload
实际值的计算类似于
(payload << 4) | (select << 1) | start
因此,您的位字段以uint8
的次要部分开头。它与系统的低端顺序无关,因为低端顺序定义了uint16
,uint32
等字节的字节顺序。
字节内位域的位顺序由编译器定义。例如,如您的示例中的MSVC uses low-to-high order。
答案 2 :(得分:2)
二进制值133和168
133 = 10000101
168 = 10101000
假定实际对齐方式与您假定的对齐方式不同。
似乎是按以下方式安排的:
---- --- -
all
payload select start
您假设以下顺序
- --- ----
start all payload
我还认为不同的编译器具有不同的对齐方式。