• 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
    ", 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,打印结果就会是正数了。
  • 相关阅读:
    《算法竞赛进阶指南》0x07贪心 POJ2054 color the tree树的缩点与合并
    《算法竞赛进阶指南》0x07 贪心 NOIP2012 vector模拟高精度计算
    《算法竞赛进阶指南》0x07贪心 POJ1328
    《算法竞赛进阶指南》0x07贪心 POJ3190
    《算法竞赛进阶指南》0x07贪心 POJ3614
    《算法竞赛进阶指南》0x06倍增 Acwing GeniusACM
    8.装饰模式(Decorator Pattern)
    7.桥接模式(Bridge Pattern)
    6.适配器模式(Adapter Pattern)
    5.原型模式(Prototype)
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/10445238.html
Copyright © 2020-2023  润新知