C语言枚举详解

枚举的引入

枚举是C语言中的一种基本数据类型,它可以让数据更简洁,更易读。

枚举语法定义格式为:

​​​​​​​enum 枚举名
{
    枚举元素1,枚举元素2,……     //注意,各元素之间用逗号隔开
};                            //注意,末尾有分号;

枚举是用来干嘛的?
枚举在C语言中其实是一些符号常量集。直白点说:枚举定义了一些符号,这些符号的本质就是int类型的常量,每个符号和一个常量绑定。这个符号就表示一个自定义的一个识别码,编译器对枚举的认知就是符号常量所绑定的那个int类型的数字。
一般情况下我们都不明确指定这个符号所对应的数字,而让编译器自动分配。

编译器自动分配的原则是:从0开始依次增加。如果用户自己定义了一个值,则从那个值开始往后依次增加。

C语言为何需要枚举?

C语言没有枚举是可以的。使用枚举其实就是对一些数字进行符号化编码,这样的好处就是编程时可以不用看数字而直接看符号。符号的意义是显然的,一眼可以看出。而数字所代表的含义除非看文档或者注释。

这么看来,宏定义也能实现呀!要专门弄个枚举类型干嘛?

宏定义和枚举有内在联系,宏定义和枚举经常用来解决类似的问题,他们俩基本相当可以互换,但是有一些细微差别。

宏定义和枚举的区别:
1、枚举是将多个有关联的符号封装在一个枚举中,而宏定义是完全散的。也就是说枚举其实是多选一,而且只能在这里面选,有时候有效防止其他不符数据的输入。
2、什么情况下用枚举?当我们要定义的常量是一个有限集合时(譬如一星期有7天,譬如一个月有31天,譬如一年有12个月····),最适合用枚举。(其实宏定义也行,但是枚举更好)
3、不适合用枚举的情况下(比如定义的常量符号之间无关联,或者无限的)用宏定义。

宏定义示例:

#define MON  1
#define TUE   2
#define WED  3
#define THU   4
#define FRI    5
#define SAT   6
#define SUN   7

枚举示例:

enum DAY
{
     MON=1, TUE, WED, THU, FRI, SAT, SUN
};

总结:宏定义先出现,用来解决符号常量的问题;后来人们发现有时候定义的符号常量彼此之间有关联(多选一的关系),用宏定义来做虽然可以但是不贴切,于是乎发明了枚举来解决这种情况。

类型定义和变量声明

枚举类型需要先定义后使用,这里的定义是类型的定义,不是枚举变量的定义。

既然枚举也是一种数据类型,那么它和基本数据类型一样也可以对变量进行声明。

方法一:枚举类型的定义和变量的声明分开

//先定义类型
enum DAY    //类型名称就是enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

//后声明变量
enum DAY yesterday;
enum DAY today;
enum DAY tomorrow; //变量tomorrow的类型为枚举型enum DAY
enum DAY good_day, bad_day; //变量good_day和bad_day的类型均为枚举型enum DAY

方法二:类型定义与变量声明同时进行

enum //跟第一个定义不同的是,此处的标号DAY省略,这是允许的。
{
    saturday,
    sunday = 0,
    monday,
    tuesday,
    wednesday,
    thursday,
    friday
} workday; //变量workday的类型为枚举型enum DAY

//变量days的类型为枚举型enum week
enum week { Mon=1, Tue, Wed, Thu, Fri Sat, Sun} days; 

//定义枚举类型并声明了两个枚举型变量
enum BOOLEAN { false, true } end_flag, match_flag; 

第二种方式的变量定义是一次性的,后面要想再定义同类型变量就不行了。

第一种方式更灵活。

方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明

typedef enum workday
{
    saturday,
    sunday = 0,
    monday,
    tuesday,
    wednesday,
    thursday,
    friday
} workday; //此处的workday为枚举型enum workday的别名

//或者
//enum workday中的workday可以省略
typedef enum
{
    saturday,
    sunday = 0,
    monday,
    tuesday,
    wednesday,
    thursday,
    friday
} workday; //此处的workday为枚举型enum workday的别名


//定义变量
//变量today和tomorrow的类型为枚举型workday,也即enum workday
workday today, tomorrow; 

注意:

同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常量。

使用枚举变量

1、先声明后赋值(常用)

#include<stdio.h>

/* 定义枚举类型 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };

void main()
{
    /* 使用基本数据类型声明变量,然后对变量赋值 */
    int x, y, z;
    
    x = 10;
    y = 20;
    z = 30;
    
    /* 使用枚举类型声明变量,再对枚举型变量赋值 */
    enum DAY yesterday, today, tomorrow;
    
    yesterday = MON;
    today     = TUE;
    tomorrow  = WED;

    printf("%d %d %d \n", yesterday, today, tomorrow);
}

就像各种类型都有取值范围一样,枚举变量只能接收枚举类型中定义好的符号值(实质是一个int类型的数据)。

2、声明的同时赋值

#include <stdio.h>

/* 定义枚举类型 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };

void main()
{
    /* 使用基本数据类型声明变量同时对变量赋初值 */
    int x=10, y=20, z=30;

    /* 使用枚举类型声明变量同时对枚举型变量赋初值 */
    enum DAY yesterday = MON, 
             today = TUE,
             tomorrow = WED;

    printf("%d %d %d \n", yesterday, today, tomorrow);
}

3、类型定义、变量声明和赋值同时进行(不推荐,会引入全局变量)

#include <stdio.h>

/* 定义枚举类型,同时声明该类型的三个变量,并赋初值。它们都为全局变量 */
enum DAY
{
    MON=1, 
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN 
}
yesterday = MON, today = TUE, tomorrow = WED;

/* 定义三个具有基本数据类型的变量,并赋初值。它们都为全局变量 */
int x = 10, y = 20, z = 30;

void main()
{
    printf("%d %d %d \n", x, y, z); //输出:10 20 30
    printf("%d %d %d \n", yesterday, today, tomorrow); //输出:1 2 3
}

补充

对枚举型的变量可以直接赋任意整数值,如果赋值浮点数,也会自动去掉小数部分。

赋整数值时,可直接赋值,因为枚举的本质就是整型(int)数据的集合。

#include <stdio.h>

int main()
{	
	enum week
	{
		MON, TUE, WEN
	};
	
	enum week oneday = 100;
	
	printf("%d,Hello, World! \n", oneday); //100,Hello, World! 
}

其实,更正规的做法是进行显式的强制类型转换:

#include <stdio.h>

int main()
{	
	enum week
	{
		MON, TUE, WEN
	};
	
	enum week oneday = (enum week)100;
	
	printf("%d,Hello, World! \n", oneday); //100,Hello, World! 
}

但是不强制转换也可以,和第一个示例一样,不加的话就是隐式类型转换,不会出错。

枚举变量既可以定义变量使用,也可以直接使用:

#include <stdio.h>

int main()
{	
	enum week
	{
		MON, TUE, WEN
	};
	
	enum week oneday = MON;
	
	printf("%d,Hello, World! \n", oneday); //0,Hello, World! 
	printf("%d,Hello, World! \n", WEN);//2,Hello, World!
}

直接使用枚举的情况更常见,因为一旦通过变量,那么就可以赋任何值,那就失去了枚举的意义了,本来枚举就是为了放一些特定整数集合的数据类型,值一般是固定的,比如对错、比如星期、比如状态等等。

switch中不能对枚举进行判断

switch中只能对整型值做判断。

此时,需要使用常规的if判断。

//开发时,当地址顺序和序号顺序一致时,可更加方便操作,因为序号++或者--,对应的地址也可以++或者--
//枚举的序号也是连续的,数组的序号也是连续的,这点有时可以好好利用下。
//总之,编程时,多利用连续性,有时会让代码变得更简洁。 

在C语言中,枚举类型的sizeof大小是4字节,且与枚举的个数没有关系。

枚举类型(enum)在C语言中用于定义一组命名的整型常量。枚举类型的大小并不是固定的,而是依赖于底层的整型大小。在大多数情况下,枚举类型被当作int类型来处理,其大小通常是4个字节。这是因为枚举类型的值通常不会超过int类型的范围。

<think>好的,我需要回答用户关于C/C++中枚举和#define宏区别的问题。首先,我要回忆已有的知识,并参考用户提供的引用内容。 首先,用户给出的引用[^1]提到,#define宏在预编译阶段替换,而枚举在编译时确定值。这点很重要,说明枚举有类型检查,而宏只是文本替换。比如调试时,枚举可以显示名称,宏只能看到替换后的值。同时,枚举可以一次定义多个相关常量,而宏必须逐个定义。另外,枚举支持自增,方便连续定义,而宏需要手动设置每个值。 引用[^2]补充了宏的习惯写法是大写,以及可以用来定义数据类型,但可能带来类型安全的问题。比如用宏定义PI为int,但实际使用时可能不符合预期。而枚举在C++中类型更明确,尤其是在C++11后可以指定底层类型,如引用[^4]所述。 引用[^3]提到在头文件中同时包装C风格枚举和接口的问题,这可能涉及兼容性,但暂时可能不需要深入,除非用户问到。引用指出C和C++在枚举底层类型上的差异,C中枚举默认是int,而C++11允许指定类型,这增加了枚举的灵活性。 接下来,我需要组织这些点,分项比较两者的区别。例如作用阶段、调试支持、批量定义、类型安全、作用域等。同时要结合例子,比如用枚举定义颜色,而宏可能单独定义每个颜色值。另外,类型安全方面,枚举在C++中可以作为类型检查,防止错误赋值,而宏没有这种保护。 可能还需要提到宏的灵活性,比如可以定义更复杂的表达式,而枚举只能是整型常量。但这也带来潜在的问题,比如替换错误。同时,作用域方面,枚举的常量在枚举作用域内,而宏是全局的,可能导致命名冲突。 需要确保每个区别点都有引用支持,比如提到调试和批量定义,关于类型定义,关于底层类型。然后,将各个点清晰列出,使用用户要求的格式,行内数学表达式用$...$,但这里可能不涉及数学公式,所以注意语法正确即可。 最后,生成相关问题,可能涉及使用场景、优化、类型安全等。需要确保问题相关且符合用户示例中的结构。</think>### C/C++中枚举(enum)与#define宏的区别及用法比较 #### 1. **作用阶段不同** - **#define宏**:在预编译阶段进行**简单文本替换**,例如`#define PI 3.14`会被替换为字面值3.14。这可能导致调试困难,因为调试器无法识别宏名称[^1]。 - **枚举**:在**编译阶段**确定值,枚举常量具有明确的类型(如C++中默认为`int`,C++11后可指定类型),编译器会进行类型检查[^4]。 #### 2. **类型安全** - **枚举**:在C++中属于独立的数据类型,赋值时需显式转换。例如: ```cpp enum Color { RED, GREEN }; Color c = RED; // 正确 c = 1; // 错误(C++中需强制类型转换) ``` - **#define宏**:无类型检查,仅替换文本,可能导致意外错误: ```cpp #define RED 0 int color = RED; // 替换为字面值0,无类型约束 ``` #### 3. **批量定义与自增特性** - **枚举**:支持一次性定义一组相关常量,且可自动递增。例如: ```cpp enum Week { Mon=1, Tue, Wed }; // Mon=1, Tue=2, Wed=3 ``` - **#define宏**:需手动定义每个值: ```cpp #define Mon 1 #define Tue 2 #define Wed 3 ``` #### 4. **作用域管理** - **枚举**:C++中枚举常量默认属于枚举类型的作用域(C++11引入`enum class`进一步限制作用域): ```cpp enum class Color { RED, BLUE }; Color c = Color::RED; // 需作用域限定符 ``` - **#define宏**:全局替换,可能导致命名冲突: ```cpp #define RED 0 void func() { int RED = 1; } // 错误:宏替换后变为 int 0 = 1; ``` #### 5. **调试与可读性** - **枚举**:调试时可显示符号名称(如`RED`),提升代码可读性。 - **#define宏**:调试时仅显示替换后的字面值(如0),难以追踪含义。 #### 6. **底层类型控制** - **枚举**:C++11允许指定底层类型(如`enum : uint8_t { ... }`),优化内存占用。 - **#define宏**:无此功能,仅依赖替换后的值类型。 #### 总结表格 | 特性 | 枚举(enum) | #define宏 | |---------------------|-----------------------------------|-----------------------------| | **作用阶段** | 编译时 | 预编译时替换 | | **类型安全** | 支持(C++) | 无 | | **批量定义** | 支持(自动递增) | 需逐个定义 | | **作用域** | 受限(C++11的`enum class`更严格) | 全局替换,易冲突 | | **调试支持** | 显示符号名称 | 显示替换后的字面值 | | **底层类型控制** | C++11支持指定类型 | 无 |
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值