重学C语言——宏

小鸡
阅读156 喜欢0 C语言 更新2019-9-14

由于实习期间用的一直是C语言,最近又开始重新学了一下C,认识一些以前没注意到的,但是也比较经常用到特性,比如宏定义。C语言的宏有以下几类:

  1. 定义宏
  2. 包含头文件的宏
  3. 条件编译宏
  4. 其他预处理关键字

定义宏

比如

#define MAX 100

用来定义一个常量,也可以用来定义一个宏函数

#define MAX(a, b) a:b?a>b

其实宏定义就是一个简单的字符串替换,将前面的字符串替换成后面的字符串。

#define name "levy"

包含头文件的宏

用一个include表示,引入的头文件有两种区别

#include <stdio.h>

引入编译器自带的头文件,编译的时候会在编译器的bin目录下面查找。

#include "mySource.h"

引入编程人员自定义的头文件,编译的时候在相对路径下查找。

而这些引入的头文件其实是做一个源码替换,预编译的时候将那些.h文件中的代码替换到头文件引入的位置进行编译。

条件编译宏

在编译的时候进行条件判断,决定哪些代码会被编译,哪些代码会被忽视。常用到的有以下几类

  1. #ifdef
  2. #elif
  3. #ifndef
  4. #else
  5. #endif
  6. #if

#ifdef

#define begin

#ifdef begin
printf("开始编译代码1");

#else
printf("开始编译代码2");

#endif

上面的代码,执行编译的时候,代码1的输出会被编译,而代码2的输出会被忽略,因为这里做了一个判断begin这个宏是否定义了,如果定义了就编译第一段代码,如果没定义就编译第二段。

#ifndef

这个控制宏常用于头文件的引用。当我们自定义一个头文件的时候,可能发生重复应用的情况,导致里面的函数和数据重复定义。

比如有4个文件,分别为test1.hb.hc.htest.c

head.h

int a = 1;

b.h

#include "head.h"
int b = 1;

c.h

#include "head.h"
int c = 1;

test.c

#include "b.h"
#include "c.h"

当编译器进行预编译之后,test.c就会出现重复定义的情况

int a = 1;
int b = 1;
int a = 1;
int c = 1;

所以当我们自定义一个头文件的时候,最好进行防重复引用的操作。我们可以这样改写head.h

#ifndef head
#define head
int a = 1;
#endif

这样的话,当head.h被多次引用时,因为head这个宏已经定义了,就不会继续编译下面的代码

#if

顾名思义,这也是一个简单粗暴的编译判断。

#if 1+1=2
...

根据后面逻辑表达式的值来判断是否进行下面的编译

编译的控制宏常用的就是这些,至于这些东西有什么用呢?根据我最近学习的经验,编译控制宏常用于以下场景。

想要用一套代码编译两种产品,但是两种产品在代码中有多处细微的不同,每次编译的时候,切换产品需要一处一处修改太过繁琐,需要一个控制宏作为代码中的开关,决定编译的时候生成的是哪个产品的代码