由C语言位域(冒号)谈C语言的结构体、枚举、共用体

时间:2022-06-06 10:46:25

综述

今天看到一行代码

unsigned char busy:1;

不太明白 : 的作用,百度了几分钟,发现是结构体中位域操作符,深感平时工作疏于学习,以至于这么简单的问题还不知道,所以写了这篇文章,以作为复习。


1、关于位域

有些信息在储存时,并不需要占用一个完整的字节,而只需占几个或一个二进制位,例如存放一个开关常量,只有0和1两种状态,用一个二进制位即可满足要求,无需浪费空间,并且可以使处理更加简便,所以C语言提供了一种数据结构,成为位域(或位段)。这样就可以把几个不同的对象用一个字节的二进制位域来表示。所谓“位域”就是是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。

每一个域有一个域名,允许在程序中按域名进行操作。位域主要用于结构体。

struct temp  
{  
int a:8;  
int b:2;  
int c:6;  
}data; 
在上面的代码中,data占2个字节。位域的两个特点如下:

1.1. 一个位域必须存储在同一个字节中,不能跨两个字节。如果一个字节所剩空间不够存放另一个位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

struct temp
{
char a:4
char :0 //空域
char b:4 //从下一单元开始存放
char c:4
}
其中,a占第一个字节的4位,后4位填零不用,b从第二个字节开始,占4位,c占剩下4位。

1.2. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:

struct temp
{
char a:4
char :2 //空域
char b:4 //从下一单元开始存放
char c:4
}

2、结构体

2.1、存在理由

描述一组具有相同类型数据的有序集合,用于处理大量相同类型的数据运算 使用构造类型——数组
描述一组具有不同类型数据的有序集合,用于处理大量不同类型的数据运算 使用构造类型——结构体

2.2、定义方式

2.2.1、先声明结构体类型再定义变量名

struct stu
{
成员列表
};
struct stu Lucy;

2.2.2、在声明类型的同时定义变量

struct stu
{
成员列表
}Lucy;

2.2.3、直接定义结构体类型变量,无类型名

struct
{
成员列表
}Lucy,Bob;
在上面三种定义结构体变量的方式中,stu为结构体类型名(第三种没有类型名),Lucy为结构体变量名。可以同时变量多个结构体变量名(如第三个)。
结构体类型名:指定了一个结构体类型(相当于char),它相当于一个模型,但其中并无具体数据,系统对之也不分配实际内存单元。
结构体变量名:实际分配空间——为了能在程序中使用结构体类型的数据,应当定义结构体类型的变量,并在其中存放具体的数据。

我们推荐使用如下方法(使用typedef重命名)其中STU为结构体类型名,Lucy与Bob为结构体变量名:

typedef struct student
{
int num;
char name[20];
char sex;
}STU;
STU Lucy,Bob;

2.4、注意事项

2.4.1、结构体变量的成员引用必须单独引用
结构体变量名.成员名
如:
Lucy.num = 101;
scanf("%c",&Lucy.sex);
printf("%s",Lucy.name);
2.4.2、允许具有相同类型的结构体变量相互赋值(多用于结构体成员整体操作,例如排序等)
Bob = Lucy;
2.4.3、结构体可以在定义的时候进行初始化
STU Lucy = {12, "hello", 'm'};
3.4、允许嵌套定义结构体变量,成员引用多级引用
Lucy.birthday.mouth = 12;
关于结构体数组和结构体指针等深层次用法,在中介绍,此处不做赘述!

3、共用体

3.1、存在理由和特点

a.同一内存段可以用来存放几种不同类型的成员,但每一瞬间只有一种起作用
b.共用体变量中起作用的才成员是最后一次存放的成员,在存入一个新的成员后原有成员的值会被覆盖
c.共用体变量的地址和它的个成员的地址都是同一地址

3.2、定义方式

和结构体非常类似,有三种定义方式,我们推荐下面这种:

typrdef union data
{
short int i; //短整型:2个字节
char ch; //字符型:1个字节
float f; //实型:4个字节
}DATA;
DATA a,b;
a.i——>引用共用体变量中的整型变量i
a.ch——>引用共用体变量中的整型变量ch
a.f——>引用共用体变量中的整型变量f

3.3、参考代码

#include<stdio.h>

//共用体
typrdef union data

{

long int x; //长整型:4个字节
char y; //字符型:2个字节
int z; //整型:4个字节
}DATA;
DATA a = {10};

int mian()
{
a.x = 5;
a.y = 6;
a.z = 15;
printf("%d\n",a.x + a.y);
return 0;
}

分析:
初始化为10(后面的修改只改变了一个字节)
10 0000 1010
5 0000 0101
6 0000 0110
15 0000 1111
打印结果是30,因为初始化和修改共用体元素,都是单位覆盖。因而这里无论是4字节的a.x还是1字节的a.y都是15,打印的结果为30(共用体所占的字节是最大的元素,也就是这个结构体占4字节)。

4、枚举

4.1、存在理由

有的时候我们需要几种可能的值(我们也可以用define来获得,或者使用const类型的变量),或者我们需要这几个变量自动的那规律来变化(如何变化见下面),比如,我们的定义中是一周7天,或者我们需要12中颜色,我们就可以使用枚举。枚举是将变量的值一一列举出来,变量的值只限于列举出来的值的范围。

4.2、定义方式

同样的枚举我们推荐用下面的定义方式

typrdef enum week//枚举类型
{
mon,tue,wed,thu,fri.sat,sun
}WEEK;
WEEK workday、weekday; //枚举变量
其中week为枚举类型名,WEEK为枚举变量名,mon,tue,wed,thu,fri.sat,sun为枚举值表,workday、weekday为枚举变量,workday与weekday只能取sun...sat中的一个。
workday = mon; //正确
weekday = tue; //正确
workday = abc; //错误,枚举中没有abc
如果没有初始化(注意下面的写法是不规范的),那么
mon = 0
tue = 1
wed = 2
...
sun = 6
我们也可以初始化
mon = -1
那么
tue = 0
wed = 1
...
sun = 5
或者我们也可以初始化
mon = 0
tue = 0
那么
wed = 1
...
sun = 5
我们可以看到,从没有定义的那个元素开始逐次增加,本质上enum是整数型(如果是java, 则不是整数型,而是一个由编译器生成的特殊的类)。

4.3、注意事项

a.枚举值是常量,不能在程序中用赋值语句对它赋值,例如sun = 5; mon = 2; sun = mon;都是错误的。
b.可以改变枚举值的默认值(上面的初始化就是这种方式),如:
enum week
{
mon = 3; tue,wed,thu,fri.sat,sun
};
那么mon等于3,tue等于4,以此类推。

4.4、事例代码

#include<stdio.h>

//枚举
typrdef enum week//枚举类型
{
sun = 2,mon,tue,wed,thu,fri.sat
}WEEK;

WEEK a,b,c;//枚举变量

enum bool
{
false,true
}bl;

int main()
{
a = sun;
b = mon;
c = ture;
printf("%d, %d, %d",a, b, c);
bl = ture;
if(1 == bl)
{
printf("bl为真\n");
}
return 0;
}
打印结果为:2,3,4bl为真。

5、结束语

结构体、共用体、枚举都是构造类型数据,我们从定义方式就可以看到他们的相似性。在结构体类型中的位段使用是值得我们注意的,如果用好了,会使我们在项目中节省很多必要的空间!【END150613】

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

版本:V1.1
时间:2015.09.19
作者:Alan
说明:修改部分错误和修改排版
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

版本:V1.0
时间:2015.06.13
作者:Alan
说明:完成文章。
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<