C :位域实现与对齐

C/C++中以一定区域内的位(bit)为单位来表示的数据成为位域,位域必须指明具体的数目。位域的作用主要是节省内存资源,使数据结构更紧凑。

REF:   https://www.cnblogs.com/pure/archive/2013/04/22/3034818.html

位数组 : https://blog.csdn.net/qq_37375427/article/details/79797359


C/C++中以一定区域内的位(bit)为单位来表示的数据成为位域,位域必须指明具体的数目。

位域的作用主要是节省内存资源,使数据结构更紧凑。

     有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作 

 

  • 一个位域必须存储在同一个字节中,不能跨两个字节,故位域的长度不能大于一个字节的长度;

struct BitField

{

      unsigned int a:4;  //占用4个二进制位;

      unsigned int  :0;  //空位域,自动置0;

      unsigned int b:4;  //占用4个二进制位,从下一个存储单元开始存放;

      unsigned int c:4;  //占用4个二进制位;

      unsigned int d:5;  //占用5个二进制位,剩余的4个bit(e)不够存储4个bit的数据,从下一个存储单元开始存放;

      unsigned int  :0;  //空位域,自动置0;

      unsigned int e:4;  //占用4个二进制位,从这个存储单元开始存放;

};

  • 取地址操作符&不能应用在位域字段上;

  • 位域字段不能是类的静态成员;

  • 位域字段在内存中的位置是按照从低位向高位的顺序放置的;

  • 位域的对齐

1. 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

2. 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

3.如果相邻的两个位域字段的类型不同,则各个编译器的具体实现有差异,VC6采取不压缩方式,GCC和Dev-C++都采用压缩方式;

4. 整个结构体的总大小为最宽基本类型成员大小的整数倍。

5. 如果位域字段之间穿插着非位域字段,则不进行压缩;(不针对所有的编译器)

 

TIP:

  • 位域变量的地址不可取

 

位域与大小端: 大端和小端都是以字节为准的。大端即高字节在低地址。

 

位域与符号:

union

{

    struct

    {

        char a:1;

        char b:2;

        unsigned char c:5;

    }d;

    unsigned char e;

}f;

    f.d.b = 0x01;

    printf("e = %x, %d\n",f.e,f.e);

    printf("a = %x, %d\n",f.d.a,f.d.a);

    printf("b = %x, %d\n",f.d.b,f.d.b);

 

            b                     e

0x01  0001  1 (0000 0001)    0010 2

0x02  0010 -2 (1111 1110)    0100 4

0x03  0011 -1 (1111 1111)    0110 6  最高位分得1,就是负数,负数用的补码.

                                     实际的值是取反加1,就是00+1=1,再取符号负数,就是-1.

0x04  0100  OUT   ...... 不能给 b 赋值 b 只有两个bit (0~3)

 

注:

无符号整型在循环条件中造成死循环

#include<stdio.h>

int main()

{

    size_t i = 10;

    while(i >= 0)

    {

        printf("%u\t", i);

        i--;               /* 当 i 为 0 时, i-- 操作导致下溢翻转,变成该整型所能表示的最大值而导致死循环 */

    }

    return 0;

}

对于无符号整数类型(unsigned char, unsigned short , unsigned int, unsigned long 以及宏定义 size_t 等),执行自减操作就会下溢而翻转,变成该整型的最大值,从而导致死循环的发生。

避免这种错误最简单的方式就是不要用无符号整数执行自减运算时与 0 进行相等比较;或者避免使用无符号整型进行此类操作。对于示范代码,将 ”size_t“  改成 ”int", 或者修改 “ while(i >= 0)" 为 " while(i > 0)"的判断(当然判断条件的意思也变了)。

大正整数相加上溢,大负整数相减下溢

a = 2147483647,   a + 1 = -2147483648

b = -2147483648,  b - 1 = 2147483647

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章