C语言的编译预处理和宏
预处理
C语言的编译系统一般都包括预处理、编译和链接等部分,C代码编译时编译器一般的处理过程如下:
首先,运行预处理程序扫描源代码,对源程序中的预处理命令进行转换和处理
然后,运行编译程序,把源程序编译成目标代码
最后,运行链接程序,把目标代码链接成可执行文件
即替换,编译,链接三个过程
其中提到的预处理命令是指以**#号**开头的命令。在预处理过程中,这部分代码会被编译器索引处理成为我们所需要的代码段。
比如说使用
#include <math.h>
编译时,编译器会自动把math.h头文件中的code加入程序中,使我们的程序可以调用库中的函数。
不带参数的宏
而除去#include之外,还有一种比较常用的写法就是#define,我们称之为宏定义,比如
#define PI 3.14159
在程序编译过程中,PI会被自动替换为浮点数3.14159
当然,这是最为简单的宏定义的用法,即不带参数的宏,就是实现了简单的替换功能。在编程过程中,如果遇到了需要使用PI,RE,PR等量时,就可以考虑使用。这种用法可方便我们对代码的阅读和维护
这种宏的用法有以下几个需要注意的点:
1.宏定义一行写不下时,可以用换行标记""来续行,例如:
#define LONG_STRING this is\
not a very long string
2.字符常量、字符串和字符串中出现宏名,则不会被替换。例如:
#define HI hello
printf("HI");
3.宏定义是允许嵌套的,灵活性比较高。例如:
#define X 5
#define Y X+1
#define Z Y*X
a = Z;
实际上a相当于做了一个运算的结果
代参数的宏
代参数的宏的使用方法有点类似函数,最简单的使用方法如下:
#define MULT(a,b) a*b
res = MULT(3,4)
这里的第二行相当于进行了一次相乘操作,然后把结果赋值给a。需要注意的是这种函数的调用方式可能会出现逻辑上的错误,比如:
#define MULT(a,b) a*b
res = MULT(3+2,4+5)
我们的逻辑语义会理解为,先做两个加法运算,再做乘法运算。然而实际编译过程中,被替换为代码:res = 3+2*4+5
。实际上运行时,会先执行乘法运算,再执行两次加法。为了保证这种使用方法不会出现类似这样的逻辑错误,最好定义时使用如下:
#define MULT(a,b) (a)*(b)
使用宏的定义方式和调用函数有什么区别呢?
1.首先,函数调用时,实参要和形参的数据类型保持一致,不一致时,系统会自动把实参转换为形参的类型。但是宏只相当于简单的替换某个函数形式,不存在数据类型对应的问题
2.在编译过程中,带参数的宏对应的代码就已经被替换,实际执行过程中,相当于执行普通的代码。但是调用子函数的过程中,会出现压栈传参清栈的过程。使用宏定义一些简单的函数来实现子函数的功能,可以大大提高程序运行速度。
取消宏定义
常见的#define PI 3.14
这样的命令,从开始到文件结束处都有效。有时全局有效的宏定义也会造成一些麻烦,而取消宏的命令,则可以把这种全局的宏局部化。
#define PI 3.14
#undef PI
#define PI 3.14159
宏定义和inline函数的区别
https://blog.csdn.net/wangliang888888/article/details/77990650
部分参考了这篇博客的内容。
inline函数的作用和宏定义非常像,我们首先看一下使用方法:
inline int MULT(int a,int b)
{
return a*b;
}
res = MULT(3,4);
inline函数也会进行代码的替换,但是替换之前会进行对应的语法检查,并且输入量也会有数据类型,相对宏定义更加安全,但是会消耗更多的内存空间。
程序包含多个.cpp文件时的实现和编译过程中是否会真正实现代码的替换。这部分细节可以具体的参考链接中的帖子。
多个文件中的函数相互调用
当程序中包含两个源文件时,如果第二个文件默认可以调用第一个文件中的函数,例如:
//File1.cpp
extern int eMax(int x, int y)
// extern可以省略
{
return x>y?x:y ;
}
//File2.cpp
void main()
{ int M;
extern int eMax(int,int);
// extern可以省略
M=eMax(6,2);
}
2文件可以调用1文件中的程序,我们称之为外部链接,外部链接是默认的属性。有时为了保证局部属性,我们会使用内部链接,如下:
//File3.cpp
static int iMax(int x, int y)
{
return x>y?x:y ;
}
//File4.cpp
void main()
{
int M;
int iMax(int,int);
M=iMax(6,2);
}
此时4调用3中的函数就会报错。