枚举
枚举顾名思义就是一一列举。
把可能的取值一一列举。
比如我们现实生活中:
一周的周一到周日是有限的7天 ,可以一一列举。
在实际驱动开发中,枚举类型常用于状态吗以及错误码等类型的列举例如
/* Error Codes */
enum i40e_status_code {
I40E_SUCCESS = 0,
I40E_ERR_NVM = -1,
I40E_ERR_NVM_CHECKSUM = -2,
I40E_ERR_PHY = -3,
I40E_ERR_CONFIG = -4,
I40E_ERR_PARAM = -5,
I40E_ERR_MAC_TYPE = -6,
I40E_ERR_UNKNOWN_PHY = -7,
I40E_ERR_LINK_SETUP = -8,
I40E_ERR_ADAPTER_STOPPED = -9,
I40E_ERR_INVALID_MAC_ADDR = -10,
I40E_ERR_DEVICE_NOT_SUPPORTED = -11,
I40E_ERR_PRIMARY_REQUESTS_PENDING = -12,
I40E_ERR_INVALID_LINK_SETTINGS = -13,
I40E_ERR_AUTONEG_NOT_COMPLETE = -14,
I40E_ERR_RESET_FAILED = -15,
I40E_ERR_SWFW_SYNC = -16,
I40E_ERR_NO_AVAILABLE_VSI = -17,
I40E_ERR_NO_MEMORY = -18,
I40E_ERR_BAD_PTR = -19,
I40E_ERR_RING_FULL = -20,
I40E_ERR_INVALID_PD_ID = -21,
I40E_ERR_INVALID_QP_ID = -22,
I40E_ERR_INVALID_CQ_ID = -23,
I40E_ERR_INVALID_CEQ_ID = -24,
I40E_ERR_INVALID_AEQ_ID = -25,
I40E_ERR_INVALID_SIZE = -26,
I40E_ERR_INVALID_ARP_INDEX = -27,
I40E_ERR_INVALID_FPM_FUNC_ID = -28,
I40E_ERR_QP_INVALID_MSG_SIZE = -29,
I40E_ERR_QP_TOOMANY_WRS_POSTED = -30,
I40E_ERR_INVALID_FRAG_COUNT = -31,
I40E_ERR_QUEUE_EMPTY = -32,
I40E_ERR_INVALID_ALIGNMENT = -33,
I40E_ERR_FLUSHED_QUEUE = -34,
I40E_ERR_INVALID_PUSH_PAGE_INDEX = -35,
I40E_ERR_INVALID_IMM_DATA_SIZE = -36,
I40E_ERR_TIMEOUT = -37,
I40E_ERR_OPCODE_MISMATCH = -38,
I40E_ERR_CQP_COMPL_ERROR = -39,
I40E_ERR_INVALID_VF_ID = -40,
I40E_ERR_INVALID_HMCFN_ID = -41,
I40E_ERR_BACKING_PAGE_ERROR = -42,
I40E_ERR_NO_PBLCHUNKS_AVAILABLE = -43,
I40E_ERR_INVALID_PBLE_INDEX = -44,
I40E_ERR_INVALID_SD_INDEX = -45,
I40E_ERR_INVALID_PAGE_DESC_INDEX = -46,
I40E_ERR_INVALID_SD_TYPE = -47,
I40E_ERR_MEMCPY_FAILED = -48,
I40E_ERR_INVALID_HMC_OBJ_INDEX = -49,
I40E_ERR_INVALID_HMC_OBJ_COUNT = -50,
I40E_ERR_INVALID_SRQ_ARM_LIMIT = -51,
I40E_ERR_SRQ_ENABLED = -52,
I40E_ERR_ADMIN_QUEUE_ERROR = -53,
I40E_ERR_ADMIN_QUEUE_TIMEOUT = -54,
I40E_ERR_BUF_TOO_SHORT = -55,
I40E_ERR_ADMIN_QUEUE_FULL = -56,
I40E_ERR_ADMIN_QUEUE_NO_WORK = -57,
I40E_ERR_BAD_IWARP_CQE = -58,
I40E_ERR_NVM_BLANK_MODE = -59,
I40E_ERR_NOT_IMPLEMENTED = -60,
I40E_ERR_PE_DOORBELL_NOT_ENABLED = -61,
I40E_ERR_DIAG_TEST_FAILED = -62,
I40E_ERR_NOT_READY = -63,
I40E_NOT_SUPPORTED = -64,
I40E_ERR_FIRMWARE_API_VERSION = -65,
I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR = -66,
};
上面这段代码是intel710网卡驱动的中关于错误码的定义,使用的是枚举类型。
枚举类型的定义
以性别举例
//枚举类型
enum Sex{
MALE,
FEMALE,
SECRET
};
int main(){
enum Sex s= MALE;
return 0;
}
关键字是enum 里面的成员变量可以自己定义是常量。
如果不给值,那么就从第一个成员变量MALE=0开始依次递增,FEMALE就是1 SECRET就是2。定义很简单。
枚举的优点
根据我上面给出的性别枚举的例子,大家会想我们也可以使用#define定义常量,不一定非得使用枚举啊,那为什么要有枚举,就涉及到了枚举类型的优点了。
1.增加代码的可读性和可维护性。
比如上面那个intel710中的错误代码的定义,如果使用#define那么每增加一个都要多写一个如果有几十个甚至上百个,那就要写很多#define而且最好还得写在同一个地方不是很方便维护,可读性也差
2.和#define定义的标识符相比,枚举有类型检查,更加严谨。
3.防止了命名污染(封装)。
4.遍于调试。
5.使用方便,一次可以定义多个常量。
联合体-共用体
联合类型的定义
联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间(所以联合也叫共用体)
union Un{
char c;
int i;
};
这个Un就是一个联合体,我们发现它的定义方式似乎跟结构体 和枚举类型都很像,是的,从形式上看他们定义方式都是
关键字 名称{
成员变量;
};
联合体的特点
联合体的成员共用同一块内存空间,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
union Un{
char c;
int i;
};
int main(){
union Un u;
printf("%d\n",sizeof u);
}
看上面这段代码,我们可以自己算一下,这个联合体会占据多少个字节的内存空间。
如果按照成员变量的大小去计算,char类型1个字节,int 类型4个字节,那这个共用体就是5个字节,但结果是这样吗?
这个输出的结果是:
结果为什么会是4呢?那么这里就要讨论到联合体的特点了。
在此之前我们先执行如下代码
union Un{
char c;
int i;
};
int main(){
union Un u;
printf("%d\n",sizeof u);
printf("%p\n",&u);
printf("%p\n",&(u.c));
printf("%p\n",&(u.i));
}
最后的输出结果是:
那也就意味着联合体u 以及他的成员变量所用的地址都是相同的地址。
所以联合体的特点就是他们共用同一段空间。
我们假设这三个内存4个字节的空间是同一块空间,那么u指向这个空间的起始地址,c从起始地址数第一个字节,那么i从起始地址数前4个字节。所以我们可以看到c和i共用了一段空间。所以这才叫做联合体(共用体)。
所以因为这个特点会节省空间但是同样的在用法上,你只能同时用联合体之中的某一个。用c就不能用i,用i就不能用c。
判断当前计算机的大小端存储(大小端字节序问题)
(讨论一个数据,放在内存中的存放的字节顺序)
int a=0x11223344;//从左到右是高字节->低字节
//低地址 ---------------------------->高地址
// ..[][][][][11][22][33][44][][][][][][].. 大端字节序存储模式
// ..[][][][][44][33][22][11][][][][][][].. 小端字节序存储模式
最简单的实现方式:
int check_sys(){
int a=1;//00000001
return *(char*)&a;
}
int main(){
int ret=check_sys();
if(1==ret){
printf("小端\n");
} else{
printf("大端\n");
}
}
给一个int类型赋值1,然后强转为char类型,然后取地址的第一位如果是0那么就是大端存储,如果第一位是1那么就是小端存储。也就是低字节存储在了低地址中。
内存空间分布如下
除此之外,我们可不可以利用联合体的来实现大小端的区分呢?
int new_check_sys(){
union Un{
char c;
int i;
}un;
un.i=1;
//返回1,表示小端
//返回0,表示大端
return un.c;
}
int main(){
int ret=new_check_sys();
if(1==ret){
printf("小端\n");
} else{
printf("大端\n");
}
}
我们创建一个联合体,里面只存char类型和int类型,给int类型赋值1,取char类型如果是1则是小端存储,如果是0则是大端存储。
联合大小的计算
联合的大小至少是成员变量最大的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union Un{
int a;
char arr[5];
};
int main(){
union Un u;
printf("%d\n",sizeof u);//8
}
输出结果为8:
那么联合体中的a占4个字节,arr占据5个字节,char类型数组的最大对齐数就是其成员char类型的最大对齐数也就是1,而int类型的最大对齐数为4,所以最大对齐数要为4的倍数,
又因为4不满足arr[5]5个字节的要求所以就要到下一个4的倍数,也就是8所以这个联合体的大小为8。
可以把char类型数组换成int类型数组如下
union Un{
int a;
int arr[5];
};
int main(){
union Un u;
printf("%d\n",sizeof u);//20
}
结果就是20了。