宏定义(#define),枚举类型(enum 关键字), typedef

宏定义(#define)

概念

#define 叫做宏定义命令,它也是 C 语言预处理命令的一种。所谓宏定义,就是用一个标识符来表示一个字符串,如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。

无参宏定义

宏定义的一般形式为:

#define 宏名 字符串

#表示这是一条预处理命令,都是预处理器来处理的所有的预处理命令都以 # 开头。 宏名是标识符的一种,命名规则和变量相同。 字符串可以是数字、表达式、 if 语句、函数等。

这里所说的字符串是一般意义上的字符序列,不要和 C 语言中的字符串等同,它不需要双引号。

举个例子

一:
在这里插入图片描述
注意第 6 行代码 int sum = 20 + N, N 被 100 代替了。
#define N 100 就是宏定义, N 为宏名, 100 是宏的内容(宏所表示的字符串)。
原理:在预处理阶段,对程序中所有出现的“宏名”,预处理器都会用宏定义中的字符串去代换,这称为“宏替换”或“宏展开”。宏定义是由源程序中的宏定义命令#define 完成的,宏替换是由预处理程序完成的。

二:
在这里插入图片描述
在这里插入图片描述
注意在宏定义中表达式(nn+3n)两边的括号不能少,否则在宏展开以后可能会产生歧义

反面例子,
在这里插入图片描述
因为你定义的时候是什么样传进去就是什么样,凡是多项尽量都加上括号

#define 用法的几点说明

1 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单粗暴的替换。字符串中可以含任何字符,它可以是常数、表达式、 if 语句、函数等,预处理程序对它不作任何检查,如有错误,只能在编 译已被宏展开后的源程序时发现。

2 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起替换。

3 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef 命令。例
如:在这里插入图片描述

4 代码中的宏名如果被引号包围,那么预处理程序不对其作宏代替,例如:
在这里插入图片描述

5.宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换。例如: 在这里插入图片描述
在这里插入图片描述

6 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。

在这里插入图片描述

注意:用宏定义表示数据类型和用 typedef 定义数据说明符的区别:

宏定义只是简单的字符串替换,由预处理器来处理

而 typedef 是在编译阶段由编译器处理的,它并不是简单的字符串替换,而给原有的数据类型起一个新的名字,将它作为一种新的数据类型。

在这里插入图片描述

带参数的宏定义

在这里插入图片描述
举个例子:
在这里插入图片描述

带参宏定义的说明

在这里插入图片描述
在这里插入图片描述

2 在带参宏定义中,不会为形式参数分配内存,因此不必指明数据类型。
而在宏调用中,实参包含了具体的数据,要用它们去替换形参,因此实参必须要指明数据类型。

这一点和函数是不同的:
在函数中,形参和实参是两个不同的变量,都有自己的作用域,调用时要把实参的值传递 给形参
而在带参数的宏中,只是符号的替换,不存在值传递的问题
在这里插入图片描述
这与函数的调用是不同的,函数调用时要把实参表达式的值求出来再传递给形参,而宏展开中对实参表达式不作计
算,直接按照原样替换。

3 括号问题
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
括中括
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

枚举类型(enum 关键字)

概念

在实际编程中,有些数据的取值往往是有限的,只能是非常少量的整数,并且最好为每个值都取一个名字,以方便
在后续代码中使用,比如一个星期只有七天,一年只有十二个月,一个班每周有六门课程等。

还有在学习stm32里面的寄存器,配置它的输出速度,输入输出模式,这些都是有限的取值,所以我们可以把它们所有的取值创建一个枚举,方便以后的编程,在看到相应的枚举成员名称就可以知晓其意思,而不至于看着一大堆的0和1发憷。

过度

在不知道枚举类型时,我们用所学宏定义来实现枚举功能
在这里插入图片描述
#define 命令虽然能解决问题,但也带来了不小的副作用,导致宏名过多,代码松散,看起来总有点不舒服。
C 语言提供了一种枚举(Enum)类型,能够列出所有可能的取值,并给它们取一个名字。

类型创建

在这里插入图片描述
注意成员之间是用逗号隔开,这点与其他自定义类型不一样
在这里插入图片描述
这里假如

类型定义,初始化

定义和其他自定义类型一样
常规定义
在这里插入图片描述
简便定义
在这里插入图片描述

赋值

枚举赋值不同其他类型,在构建定义的时候就对其赋值操作了,并赋值为常数。
假如这里的web=6,Thurs没有赋值,那默认就是前一数据的基础+1;
在这里插入图片描述
举个例子:

在这里插入图片描述
在这里插入图片描述

需要注意的两点是

1 枚举列表中的 Mon、 Tues、 Wed 这些标识符的作用范围是全局的(严格来说是 main() 函数内部),不能再定义与它们名字相同的变量。

2 Mon、 Tues、 Wed 等都是常量,不能对它们赋值,只能将它的值赋给其他的变量。

枚举和宏其实非常类似:宏在预处理阶段将名字替换成对应的值,枚举在编译阶段将名字替换成对应的值。我们可以将枚举理解为编译阶段的宏

在这里插入图片描述
Mon、 Tues、 Wed 这些名字都被替换成了对应的数字。这意味着, Mon、 Tues、 Wed 等都不是变量,它们不占用数据区(常量区、全局数据区、栈区和堆区)的内存,而是直接被编译到命令里面,放到代码区,所以不能用&取得它们的地址。这就是枚举的本质。

case 关键字后面必须是一个整数,或者是结果为整数的表达式,但不能包含任何变量,正是由于 Mon、 Tues、 Wed 这些名字最终会被替换成一个整数,所以它们才能放在 case 后面
在这里插入图片描述

作为函数即返回值

在这里插入图片描述

typedef

存在的意义

C 语言允许为一个数据类型起一个新的别名,就像给人起“绰号”一样。最多情况就是原来替换自定义数据类型了。
struct

用法

普通类型用法
在这里插入图片描述
数组类型用法
在这里插入图片描述
结构体类型
在这里插入图片描述
这里其实是把 struct stu{ char name[20]; int age;char sex;} 也就是我们构建的结构体换个名字,就像int类型换名字一样,这里就是把 struct stu{ char name[20]; int age;char sex;}当成int,这里的STU不是结构体定义啊。而是取的新名字

最常用结构体用法还是,匿名结构体用法
在这里插入图片描述
像这里 struct 也像当于int 。
原本要定义变量需特殊定义,
在这里插入图片描述
指针和函数类型
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

需要强调的是, typedef 是赋予现有类型一个新的名字,而不是创建新的类型。为了“见名知意”,请尽量使用含义明确的标识符,并且尽量大写。

typedef 和 #define 的区别

typedef 在表现上有时候类似于 #define,但它和宏替换之间存在一个关键性的区别。正确思考这个问题的方法就是把 typedef 看成一种彻底的“封装”类型,声明之后不能再往里面增加别的东西。

在这里插入图片描述

2 在连续定义几个变量的时候, typedef 能够保证定义的所有变量均为同一类型,而 #define 则无法保证。这个在#define定义数据类型的时候有提到。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45830608/article/details/113029216
今日推荐