我有一个如下类型的结构体
typedef struct
{
unsigned int a : 8;
unsigned int b : 6;
unsigned int c : 2;
}x, *ptr;
我想做的是,改变c域的值。
我会执行类似以下的操作
x structure = { 0 };
x->c = 1;
当我查看内存Map时,我希望找到 00 01,但实际上我找到了 00 40。看起来像是在排列第二个字节时,它将 c 字段放在最低位,将 b 字段放在最高位。我在GCC和Windows编译器上都看到过这种情况。
现在,我所做的是以下工作,这是正常的。
unsigned char ptr2 = (unsigned char*) ptr
*(ptr2 + 1) &= 0xFC
*(ptr2 + 1) |= 0x01
我是不是看错记忆Map了?谢谢你的帮助。
6条答案
按热度按时间tzxcd3kk1#
C标准允许编译器以任意顺序放置位字段。没有可靠和可移植的方法来确定顺序。
如果你需要知道确切的位位置,最好使用无符号变量和位掩码。
下面是使用位字段的一种可能的替代方法:
fwzugrvs2#
我知道这是一个老问题,但我想补充我的想法。
1.根据我的经验,我总是看到LSB顺序的位域。这将把c:b:a的位按MSB-〉LSB顺序放置
按字节顺序读取的16位是“00 40”。从小端字节序转换过来,这是一个16位值0x 4000。
这是:
kpbwa7wx3#
存储器总是取决于底层机器结构(字节序)和编译器正在执行的打包/排列结构的策略。
uqxowvwt4#
只要您的程序有意不跨平台,您就可以依赖位字段的顺序来确定。
虽然C规范没有规定位字段的顺序,但平台的ABI规定了。在System V AMD 64的情况下,位字段的分配顺序定义为“从右到左”(第3.1.2节)。对于ARM 64,它取决于数据类型的字节序(www.example.com一节8.1.8.2)。由于您的C编译器遵循目标架构的平台ABI,因此,您可以使用在编译时,您可以依赖于给定平台中位字段的固定分配顺序。
yquaqz185#
您将C结构设置为原始位,这是您的风险。
你知道比特是什么,它们的意思是什么,所以你可以填写结构的字段。是的,它比memcpy代码多,但是如果有人添加了一个字段,它不会中断,而且它有助于在通信级别强制比特级别的特殊性。
q43xntqr6#
当我查看内存Map时,我希望找到00 01,但实际上我找到了00 40。看起来像是在排列第二个字节时,它将c字段放在最低位,将b字段放在最高位。我在GCC和Windows编译器上都看到过这种情况。
先不考虑字节序,如果你只是把所有字段排列成一个递增位的纯顺序流,你会在下面的“位流顺序”列中得到分配,你会看到结构体
c
中的最后一个字段是流中的最后一个字段。得到包括小端顺序(其实际上与纯比特流顺序相同)和三个大端顺序的四个排列。Windows编译器只支持小尾序机器(过去,内核必须处理一些大尾序机器,但所有当前的x86/x64/arm 64架构都是小尾序),并且向字段
c
(下面的位c 0)写入1将在字节1中产生1〈〈6或0 b 01000000(0x 40)。在大字节序机器上,有更多可能的排序:
1.按照从字的后面到前面的递减顺序来分配位域。2你可以在Linux上的gcc中找到这种顺序。
1.像LE一样按升序分配位域,但在字中交换整个字节。你可以在C51 8051 microcontroller compiler中找到这一点。
| 绝对位|比特流顺序|字节数|字节中的位|LE顺序|BE订单#1| BE订单#2|
| - -|- -|- -|- -|- -|- -|- -|
| 第0页|a0|第0页|第0页|a0| a0| b 0值|
| 一个|a1型|第0页|一个|a1型|a1型|第一层|
| 2个|a2型|第0页|2个|a2型|a2型|二层|
| 三个|a3型|第0页|三个|a3型|a3型|三层|
| 四个|a4格式|第0页|四个|a4格式|a4格式|b4位|
| 五个|a5格式|第0页|五个|a5格式|a5格式|b5层|
| 六个|a6格式|第0页|六个|a6格式|a6格式|零|
| 七个|a7格式|第0页|七个|a7格式|a7格式|c1型|
| 八个|b 0值|一个|第0页|b 0值|零|a0|
| 九个|第一层|一个|一个|第一层|c1型|a1型|
| 10个|二层|一个|2个|二层|b 0值|a2型|
| 十一|三层|一个|三个|三层|第一层|a3型|
| 十二个|b4位|一个|四个|b4位|二层|a4格式|
| 十三个|b5层|一个|五个|b5层|三层|a5格式|
| 十四|零|一个|六个|零|b4位|a6格式|
| 十五个|c1型|一个|七个|c1型|b5层|a7格式|