位段,枚举,联合的讲解

文章具体包括:

位段的介绍,存储方式,计算大小
枚举的介绍,使用举例
联合的介绍,存储方式,大小计算

一、位段

位段:度娘给出的解释是,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。

位段的声明和结构体很相似,但不同的是:
①位段的成员可以是int,unsigned int,signed int或者是char(属于整形家
族)类型
②位段的成员名后边有一个冒号和一个数字,这个数字表示位段所占的二进制位数。
如:

struct A
{
int _a:3;
int _b:4;
int _c:5;
int _d:6;
}a;

那么位段A多大呢?在计算之前,先说下位段怎么存储

简单说就是看变量后面的数字。先看第一个变量类型,开辟对应类型大小的字节,然后数字是多少就占多少bit,剩余bit留给下一个变量用。不够的话再开辟对应类型大小字节数。

细说的话,对于位段结构,编译器会自动进行存储空间的优化,要遵循这些原则原则:
1)如果一个位段存储单元能够存储得下位段结构中的所有成员,那么位段结构中的所有成员只能放在一个位段存储单元中,不能放在两个位段存储单元中;如果一个位段存储单元不能容纳下位段结构中的所有成员,那么从剩余的位段从下一个位段存储单元开始存放。(在VC中位段存储单元的大小是4字节).
2)如果一个位段结构中只有一个占有0位的无名位段,则只占1或0字节的空间(C语言中是占0字节,而C++中占1字节);否则其他任何情况下,一个位段结构所占的空间至少是一个位段存储单元的大小;

再看上面的例子,int类型,开辟四字节大小的空间,对于_a,_b,_c,_d,分别依次按顺序占3,4,5,6bit,最后一共占了18bit,但开辟了4字节,因此用sizeof对该结构体求大小的话是4字节。

使用位段需注意以下几点:
1)位段的类型只能是int,unsigned int,signed int三种类型,不能是char型或者浮点型;
2)位段占的二进制位数不能超过该基本类型所能表示的最大位数,比如在VC中int是占4个字节,那么最多只能是32位;
3)无名位段不能被访问,但是会占据空间;
4)不能对位段进行取地址操作;
5)若位段占的二进制位数为0,则这个位段必须是无名位段,下一个位段从下一个位段存储单元(这里的位段存储单元经测试在VC环境下是4个字节)开始存放;
6)若位段出现在表达式中,则会自动进行整型升级,自动转换为int型或者unsigned int。
7)对位段赋值时,最好不要超过位段所能表示的最大范围,否则可能会造成意想不到的结果。
8)位段不能出现数组的形式。

二、枚举

就是一一列举出相类似的东西,如星期,班级,商品等。
enum Day // 星期
{ Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
}D1,D2;
enum Class//班级
{
c1,
c2,
c3,
c4
}C1,C2;
enum Day, enum Class都是枚举类型,{}中的是枚举常量,不是变量,不能在程序中用赋值语句再对它赋值。枚举常量它们如果没有初始化的话,从第一个默认是0,后面的依次加1。如果初始化了的话,被初始化的枚举常量之前的不变,其他的根据枚举常量的值依次加1。{}后面的D,C类似结构体,是枚举变量。
需要注意的是,可以把枚举常量赋给变量,但不能把枚举常量的数值赋给枚举变量。如D1=Mon,D2=Tues;是正确的,而D1=0,D2=1;是错误的。如果非要把数值赋给枚举变量的话需要通过强制类型转换,D1=(enum Day)0;

#include
int main()
{
    int i, j;
    int mon[32];
    enum Day // 星期
    {
        Mon = 1,
        Tues,
        Wed,
        Thur,
        Fri,
        Sat,
        Sun
    };
    j = Mon;
    for (i = 1; i < 32; i++)
    {
        mon[i] = j;
        j++;
        if (j > Sun)
        {
            j = Mon;
        }
    }
    for (i = 1; i < 32; i++)//打印31天内的周一到周日
    {
        switch (mon[i])
        {
        case 1: printf(" %2d", mon[i]); break;
        case 2: printf(" %2d", mon[i]); break;
        case 3: printf(" %2d", mon[i]); break;
        case 4: printf(" %2d", mon[i]); break;
        case 5: printf(" %2d", mon[i]); break;
        case 6: printf(" %2d", mon[i]); break;
        case 7: printf(" %2d", mon[i]); break;
        default:break;
        }

        if (0 == i % 7)
        {
            printf("\n");
        }
    }
    printf("\n");
}

三、联合

联合是一种特殊的自定义类型,这种类型定义的变量包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。

union Un
 {    
int a;   
char b;
short c;
}; 

因为联合的成员是共用同一块内存空间的,所以一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

int main()
{
    union Un
    {
        int i;
        char c;
    };
    union Un un;

    //因为两个成员占用相同内存,所以地址相同
    printf("%p\n", &(un.i));
    printf("%p\n", &(un.c));

    un.i = 0x11111111;

    //因为char类型是1字节,16进制表示,char类型只能用2个数字,如果多于2个数字会发生类型截断
    un.c = 0x22;

    //‭输出286331170,因为共用一块内存且小端存储,所以本应0x11111111变为0x11111122,十进制表示‬286331170
    printf("%d\n", un.i);
}

根据上个程序可知,联合可以判断当前计算机的大小端存储。如果计算机是大端存储,则0x11111111会变为0x22111111,输出结果是‭571543825‬。
自己仿照上例写个简单的

int main()
{
    union Un
    {
        int a;
        char b;
    }u;

    u.a = 0x11;
    u.b = 0x01;

    //小端存储,结果是1;如果是大端存储则是16
    printf("%d\n", u.a);
}

计算联合结构的大小

int main()
{
    union Un1 
    {
        char a[5];  
        int b; 
    }; 

    union Un2 
    {
        short a[7];  
        int b; 
    };

    //下面输出的结果是什么? 
    printf("%d\n", sizeof(union Un1));//8
    printf("%d\n", sizeof(union Un2));//16

}

再算一题


int main()
{
    union ip_addr
    {
        unsigned long addr;   
        struct 
        {
        unsigned char c1;     
        unsigned char c2;    
        unsigned char c3;      
        unsigned char c4; 
        }ip;
    };

    union ip_addr my_ip; 
    // 176238749转换为16进制0xA 81 30 9D,因为是联合结构
    //add和结构体变量ip中的成员共用一块内存,则c1=9D,c2=30,c3=81,c4=A
    //十进制表示为10 129 48 157
    my_ip.addr = 176238749; 
    printf("%d.%d.%d.%d\n", my_ip.ip.c4, my_ip.ip.c3, my_ip.ip.c2, my_ip.ip.c1);//10.129.48.157
}

最后,还是那句,欢迎大家在评论区进行提问,提建议给我,谢谢

你可能感兴趣的:(C语言)