C语言位域解析&符号位扩展规则

复制代码
从一个例子说起:

    int main(void){  
        union{
            int i;
            struct{
                char a : 1;
                char b : 1;
                char c : 2;
            }bits;
        }num;
     
        printf("Input an integer for i(0~15): ");
        scanf("%d", &num.i);
        printf("i = %d, cba = %d %d %d\n", num.i, num.bits.c, num.bits.b, num.bits.a); 
        return 0;
    }

输入i值为11,则输出为i = 11, cba = -2 -1 -1。   为什么?

1,位域的定义

    在结构体的定义中,指定元素所占用的bit数, 并指定类型。 按照结构体的成员调用方式进行调用。

2,位域的内存对应规则

    一个字节按照从高位到低位 bit7 ~ bit0,对于位域的定义,是从低位bit0 开始算起的(注意不是从高位开始对应)。也就是说,上面例子中的位域,在一个字节中对应的存储是 0000 ccba, a在最低位,然后是b,和占两个bit的c。 c成员中按照bit3高位、bit2低位存储。

3,大小端问题

    对于小端来说,低字节存放在低地址中,int的存储从0x00地址到0x03地址,依次是 00001011 00000000 00000000 00000000。

    联合体从头开始,是对内存中数据的截断和强转, 根据刚才位域的存储结构,cc的截断是10, b和a的截断都是1。

4,为什么打印出来是负数? ---》补码的规则

    在计算机的内存中,所有的数据存储都是按照补码存储的。 对于有符号数来说,正数的补码是正数自身,负数的补码是反码+1。这都没问题。  

    问题的核心还是符号位。计算机里从低精度数向高精度数转换时,比如从char到short, 又比如这里从10两个bit填充为一个char的8个bit, 肯定会在前面扩展一些bit位,从而达到高精度数的长度。那么扩展时,是补0还是补1呢?这里有个原则就是,有符号数扩展符号位,无符号数扩展0。对应到这里也就是1。注意,这里说的是有符号数和无符号数,对于有符号的正数,因为符号位是0,所以也是补零。然而我们在位域的定义中,定义了abc都是有符号的char型。所以在向8位扩展时,因为第一位都是1,所以往前都扩展1,a和b在内存中为11111111, c为11111110,都是补码。按照%d打印出来以后, 就是-1 和 -2。 如果这里定义成 unsigned char,按照定义前面补0,打印结果就会是正数了。
复制代码

 

posted @   brave-sailor  阅读(1525)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
历史上的今天:
2018-02-27 iOS 开发 公司开发者账号,在多台Mac上合作开发,共用一个账号和证书--图文详解
2018-02-27 多台Mac电脑使用同一个apple开发者账号测试
2014-02-27 Java 计算两个日期相差月数
点击右上角即可分享
微信分享提示