爆肝一个假期的笔记补档。
这个月可能会发十几二十几篇吧。
位段
位段是通过结构体实现的。(也会有对齐之类的)
(位段以比特位作为单位)
什么是位段
位段的声明和结构是类似的,有两个不同:
位段的成员必须是char、 int、unsigned int 或signed int 。
位段的成员名后边有一个冒号和一个数字。
如
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};//8
int 是开辟空间的字节数4
:后的数字时变量所占比特位的多少。
当第一个开辟空间够用是下一个不会开辟第二个空间。
比如本题就只开辟了两个int的空间占8个字节。
位段的内存分配
- 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
- 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
- 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
例子
(因为位段不确定性我们演示VS2019的版本):
//一个例子
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
int main()
{
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
return 0;
}
位段的跨平台问题
- int 位段被当成有符号数还是无符号数是不确定的。
- 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机 器会出问题。
- 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义
- 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是 舍弃剩余的位还是利用,这是不确定的
位段可以很好的节约空间但是跨平台能力极差.我们使用位段时我们要先观察自己平台位段的规则。
对每个信息进行到比特的控制大大增加了空间的利用率。
枚举
#enum
枚举的作用和#define类似都是将字母变成常量但是枚举相较于#define更有优点
- 增加代码的可读性和可维护性
- 和#define定义的标识符比较枚举有类型检查,更加严谨。
- 防止了命名污染(封装)
- 便于调试
- 使用方便,一次可以定义多个常量
枚举的使用
enum Color//颜色
{
RED=1,
GREEN=2,
BLUE=4
};
int main()
{
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5;
return 0;
}
此代码在C编译器可以正常使用,但是在cpp编译器时会报错。
当我们不对枚举类型内元素初始化时会自动以递增的形势进行赋值从0开始。
下面对枚举不同赋值情况进行展示:
- 所有都没赋值:
- 则RED=0 GREEN =1 BLUE =2
- 对RED赋值,如RED= 1 时:
- RED=1 GREEN =2 …
- 只对GREEN赋值, 如GREEN = 2:
- RED =0 GREEN =2 BLUE = 3
我们枚举内元素均为常量不可赋值改变。
联合
#union
联合类型的定义
联合也是一种特殊的自定义类型
这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
可以观察到他们的地址相同。
union Un
{
char c;
int i;
};
//联合变量的定义
int main()
{
union Un un;
//计算连个变量的大小
printf("%d\n", sizeof(un));//4
return 0;
}
联合的特点
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
联合体大小的计算
- 联合的大小至少是最大成员的大小。
- 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
比如
union Un1
{
char c[5];
int i;
};//大小为8
union Un2
{
short c[7];
int i;
};//大小为16
第一个因为char a[5]是char类型他的对齐数为1,int类型的对齐数为4。
原本他们共用同一份空间大小为5。
但联合体大小要对齐到最大对齐数的整数倍及4的整数倍8。
第二个同理
short类型的对齐数为2 int类型对齐数为4。
原本公用一块内存大小为14(7*2)。
但要对齐到最大对齐数的整数倍及4的整数倍还要大于14所以为16。
练习
第一题
int main()
{
unsigned char puc[4];
struct tagPIM
{
unsigned char ucPim1;
unsigned char ucData0 : 1;
unsigned char ucData1 : 2;
unsigned char ucData2 : 3;
}*pstPimData;
pstPimData = (struct tagPIM*)puc;
memset(puc,0,4);
pstPimData->ucPim1 = 2;
pstPimData->ucData0 = 3;
pstPimData->ucData1 = 4;
pstPimData->ucData2 = 5;
printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
return 0;
}//02 29 00 00 注意是%x格式打印的
第二题
#include<stdio.h>
int main()
{
union
{
short k;
char i[2];
}*s, a;
s = &a;
s->i[0] = 0x39;
s->i[1] = 0x38;
printf(“%x\n”,a.k);
return 0;
}//3839