C语言小结之位段、枚举、联合体

时间:2022-09-05 21:35:18

一、位段

1.什么是位段?
位段的声明与结构体是类似的,但是有一些不同,位段的成员必须是int、unsigned int、signed int、char(数组整形家族类型),位段的成员名后边有一个冒号和一个数字。
示例:

struct A
{
    int a:2;
    int b:5;
    int c:10;
    int d:30;
};

2.位段的内存分配
①位段的成员都是属于整形家族的类型
②位段的空间上是按照需要以一个字节(char)或者四个字节(int)的方式来开辟的
③位段涉及很多不确定的因素,所以位段是不跨平台的,要注重可移值的程序应该避免使用位段

struct S{
    char a:3;
    char b:4;
    char c:5;
    char d:4;
};
printf("%d\n",struct S);

以上位段是如何在内存中存储的呢?我们现在VS下运行一下这个代码。
C语言小结之位段、枚举、联合体

这是为什么呢?我们来画个图解释一下。

C语言小结之位段、枚举、联合体
所以才存放位段A的时候,总共开辟了三次char所以位段A所占空间为3个字节。

3.位段的跨平台问题
①int位段被当成有符号数还是无符号数在不同平台下是不确定的
②位段中最大为的数目无法确定。(16位机器下最大的是16,32位机器下最大的是32,如果写成27,在16位的机器下就会出现问题)
③位段中的成员时从左向右分配还是从右向左分配的标准尚未定义
④当一个结构体包含两个位段,第二个位段成员比较大,无法容纳第一个位段剩余的位时,时舍弃还是利用,这是不确定的。

总结:跟结构体相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台问题的存在。


二、枚举

1.什么是枚举
枚举顾名思义就是意义列举,将所有的可能一一列举,比如:我们生活中的一周,以及月份,性别等等都可以一一列举。在这个时候就可以使用枚举了。

2.枚举类型的定义

enum Day
{
    Mod,
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun
};
enum Sex
{
    MALE,
    FEMALE,
    SECRET
};

以上定义的enum Day, enum Sex都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫做枚举常量。这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。
示例:

enum Color
{
    RED = 1,
    GREEN = 2,
    BLUE = 3 
};

2.枚举的优点
①增加代码的可读性以及可维护性
②跟#define定义的标识符比较枚举有类型检查,更加严谨
③防止了命名污染
④便于调试
⑤使用方便,可以一次定义多个常量

3.枚举的使用

enum Color
{
    RED = 1,
    GREEN = 2,
    BLUE = 4
};
enum Color clr = GREEN;//只能拿枚举常量来给枚举变量赋值
clr = 5

三、联合体

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

//联合体的声明
union Un
{
    char c;
    int i;
};
//联合变量的定义
union Un un;

2.联合体的特点
联合的成员是共用同一块内存空间的,这样一个联合体变量的大小,至少是最大成员的大小(因为联合体至少得有能力保存最大的成员)
示例:

union Un
{
    int i;
    char c;
};
union Un un;
//下面的结果一样吗?
printf("%d\n",&(un.i));
printf("%d\n",&(un.c));

C语言小结之位段、枚举、联合体
我们发现是一样的,也就是验证了我们所说的,联合体内的所有成员公用一块内存空间,所以他们的起始地址是一样的。

由于联合体的这个特性,所以我们可以利用联合体来解决一个问题:
判断当前计算机的大小端存储:

union Un
{
    int i ;
    char  c;
};

int main()
{
    union Un un;
    un.i = 1;

    if( 1 == un.c )
    {
        printf("此计算机是小端存储\n");
    }
    else
    {
        printf("此计算机是大端存储\n");  
    }

    return 0;
}

C语言小结之位段、枚举、联合体

3.联合大小的计算
联合的大小至少是最大成员的大小,并且当最大成员的大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

union Un
{
    char c[5];
    int i;
};
printf("%d\n",sizeof(union Un));

因为char c占了五个字节,而int i只占有四个字节,由于联合体所有成员共用一块内存,所以给这个联合体五个字节就够了,但是由于这个联合体的最大对齐数是4,而5并不是4的倍数,所以此时联合体真正的大小应该是8.
C语言小结之位段、枚举、联合体

联合与结构体的巧妙使用:

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;
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);

C语言小结之位段、枚举、联合体


欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!