0
点赞
收藏
分享

微信扫一扫

C语言自定义数据类型-枚举 联合体

枚举

枚举顾名思义就是一一列举。

把可能的取值一一列举。

比如我们现实生活中:

一周的周一到周日是有限的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个字节,但结果是这样吗?

这个输出的结果是: 

C语言自定义数据类型-枚举 联合体 _联合体

结果为什么会是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));

}

最后的输出结果是:

C语言自定义数据类型-枚举 联合体 _C_02

那也就意味着联合体u 以及他的成员变量所用的地址都是相同的地址。

所以联合体的特点就是他们共用同一段空间。

C语言自定义数据类型-枚举 联合体 _枚举_03

我们假设这三个内存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那么就是小端存储。也就是低字节存储在了低地址中。

内存空间分布如下

C语言自定义数据类型-枚举 联合体 _联合体_04

除此之外,我们可不可以利用联合体的来实现大小端的区分呢?

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:

C语言自定义数据类型-枚举 联合体 _枚举_05

那么联合体中的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了。

C语言自定义数据类型-枚举 联合体 _联合体_06

举报

相关推荐

0 条评论