深入理解C——#define与typedef
#define
名为宏定义,工作在预处理阶段,实际是对字符串的宏替换;typedef
工作在编译阶段,是对自定义数据类型的自定义别名定义。
深入理解C——#define与typedef
1 #define
1.1 概念
宏定义的实质就是替换。
宏定义在预处理阶段由预处理器进行替换,这个替换是原封不动的替换。
1.2 特点
设置宏定义时,需要特别注意括号的使用。
例如:
1 | /* 正确案例 */ |
- 因为C语言中,符号优先级在此处为:
单目运算符+/-
>双目运算符+/-
>>=
>?:
,因此实际上成了(a-b)>=0?(a-b):(-a-b)
。与原义不符。
1.3 作用
1.3.1 实现NULL在C++和C的不同定义
简例如下:
1 |
- 通过宏定义,实现编译时的自动兼容和适应替换。
- 在C++中,NULL定义为立即数0,特点是编译器不做严格类型检查;
- 在C语言中,NULL定义为(void*)型的0,特点是编译器会执行严格的类型检查,需要做好类型转换工作。
1.3.2 Debug和Release的版本控制
程序的在Debug阶段调试,会包含调试代码,用于显示输入,如:IDE中的调试时数据显示。而Release时需要去除这些冗余的调试输出代码。通过宏替换可以实现轻松的Debug/Release版本切换。
原理如下:
1 |
- 如果源代码中包含一句
#define DEBUG
,则编译前的预处理阶段,所有代码中的dbg()
调试输出函数都会被替换成printf()
显示输出函数。 - 如果源代码中没有对
DEBUG
进行宏定义,则预处理阶段会将所有的dbg()
函数替换为空白,此时,被编译的代码中不包含dbg()
调试输出语句。
2 typedef
2.1 概念
typedef
与#define
的核心区别在于处理阶段不同——#define
是预处理器识别读取并执行宏替换的宏语句,工作在编译阶段之前;typedef
是编译器实现的类型定义语句,工作在编译时。
因此,#define
眼中只有字符串的概念,只知道字符串存不存在宏定义,如何替换源代码中的字符串。而typedef
工作在编译阶段,因此存在
变量数据类型、数组、函数 等具体的语言层面的概念。
2.2 实例
2.2.1 基本数据类型
1 | ...... |
- 最简单的
typedef
应用形式,定义变量名的别名,通过#define
也可以实现。
2.2.2 数组类型
1 | ...... |
typedef
能够处理数组的语义,实际上Line
在typedef
中被定义为了一个char[81]
的”类“,因此Line t
实际上定义了一个名为t
的Line
型对象(即char[81]
字符数组对象),此处就不是简单地进行宏替换能实现的了。
2.2.3 函数
1 | ...... |
- 通过
typedef
定义了一个函数指针类型fun_ptr
,这是一个参数表为两个int
,返回值为int
的函数的函数指针类型。fun_ptr
在定义此类型的函数指针变量时,显然更加简洁明了。
2.2.4 struct结构体
1 | ...... |
- 此例,
Node
被定义为了struct node
的别名,通过typedef
简化变量定义。 - 注意:如果去除
typedef
,则按照结构体定义语法,Node
将成为该结构体类型的全局变量。
3 小结
3.1 区别#define和typedef
联系指针的概念,理解一下#define
和typedef
的区别。
1 |
|
dpChar
为宏定义,预处理阶段,该字符串dpChar
就被替换为字符串char*
,最终定义变量的结果是,p1
是char*
字符指针变量,p2
是char
字符变量。tpChar
是typedef
类型定义,编译阶段,tpChar
作为一个字符指针(char*)
类型的别名,所定义的变量p3
,p4
均为字符指针变量。