一、位段
位段和结构体的声明类似
struct A
{
unsigned char a : 3;
unsigned char b : 4;
unsigned char c : 5;
unsigned char d : 4;
};
这里我们声明了一个位段类型A,与结构体不同的是,每个成员后面都有一个冒号且都跟一个数字,其含义是该成员占用几个比特位。
位段的内存分配
- 位段的成员可以是int 、unsigned int、signed int、或者是char(属于整型家族)类型。
- 位段的空间上按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。
该例子中,struct A类型的位段一共占3个字节。
位段的使用
其他和结构体类似,可以对成员进行赋值使用。
struct A
{
unsigned char a : 3;
unsigned char b : 4;
unsigned char c : 5;
unsigned char d : 4;
};
int main()
{
struct A s = { 0 };
s.a = 1;
s.b = 2;
s.c = 3;
s.d = 4;
printf("%d\n",sizeof(s));
printf("%u %u %u %u\n",s.a,s.b,s.c,s.d);
system("pause");
return 0;
}
位段存在的问题
- 位段主要存在跨平台问题,在不同的环境下,最大比特位数不确定,如16位机器最大位是16(一次最大开辟16个比特位),32位机器最大位是32,在32位机器下可以要到27个比特位,但是16位就不行。
- 位段中的成员在内存中是从左向右分配,还是从右向左分配标准尚未定义(例子中假设从右向左分配)
- 当一个结构中第一个字节剩余的比特位是要利用起来还是舍弃还不确定(例子中舍弃)
二、枚举
枚举的定义
enum color
{
RED,
QRANGE,
YELLOW,
GREEN,
BLUE,
WHIET,
BLACK,
};
这里我们定义了枚举类型color,里面共有7个成员。
枚举的使用
enum color
{
RED,
QRANGE,
YELLOW,
GREEN,
BLUE,
WHIET,
BLACK,
};
int main()
{
enum color c = YELLOW;
system("pause");
return 0;
}
这里创建了一个enum color类型变量c,它只可以被赋值为enum color里面的成员之一。
- 本质上来说enum里面的成员都是整型。
enum color
{
RED,
QRANGE,
YELLOW,
GREEN,
BLUE,
WHIET,
BLACK,
};
int main()
{
printf("%d\n", RED);
printf("%d\n", QRANGE);
printf("%d\n", YELLOW);
printf("%d\n", GREEN);
printf("%d\n", BLUE);
printf("%d\n", WHIET);
printf("%d\n", BLACK);
system("pause");
return 0;
}
- enum中默认第一个成员的值为0,往后依次递增,当然,我们也可以赋初值。
enum color
{
RED = 1,
QRANGE,
YELLOW,
GREEN = 10,
BLUE,
WHIET,
BLACK,
};
这都是可以的,往后成员依次递增,但是为了方便,一般成员的值都是连续的。
- 枚举和宏定义差不太多,使用层面上也没什么区别。
- 使用时如果要声明的常量少且互相没有关联,就用宏,如果要声明的常量多且互相关联,就使用枚举
联合
联合的定义
union un
{
char c;
int i;
};
这里定义了一个联合类型un,共包含两个成员,char c和int i;
联合的使用
使用上和结构体一样,也用’.'操作符。
union un
{
char c;
int i;
};
int main()
{
union un a = { 0 };
a.i = 5;
printf("%d\n".a.i);
system("pause");
return 0;
}
联合的内存分配
在内存分配上,联合和结构体就有所不同了,联合的所有成员共享空间。
就是联合会开辟一块内存,所有成员共享,所以联合内的成员的起始地址都一样。
union un
{
char c;
int i;
};
int main()
{
union un a = { 0 };
printf("%p\n",&a);
printf("%p\n",&(a.c));
printf("%p\n",&(a.i));
system("pause");
return 0;
}
所以我们也可以看到这样的操作。
union un
{
char c;
int i;
};
int main()
{
union un a = { 0 };
a.i = 1;
printf("%d\n",a.c);
system("pause");
return 0;
}
这可以用来验证电脑是大端存储还是小端存储(例子中是小端)。
联合的大小
我们来看一个例子
union un
{
char a[7];
int i;
};
int main()
{
printf("%d\n",sizeof(union un));
system("pause");
return 0;
}
所以,计算联合的大小时也要注意内存对齐问题。
- 联合的大小至少是最大成员的大小
- 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
- 对齐数 = 编译器默认对齐数与该成员大小的较小值(vs默认8,Linux默认4);如果是聚合数据类型(数组和结构体),对齐数为该聚合类型中成员的最大对齐数。
在例子中,最大成员的大小是7字节,但是最大对齐数是4,7不能整除4,所以最终大小为8字节。