C语言教程(十四)预处理

1. 简介

C编译器在编译之前,会先对源程序中的代码进行预处理,称为预处理程序。预处理程序是一个单独的程序,主要处理以#开头的指令,比如宏定义、文件包含、条件编译等。

所有的预处理指令都是以#开头,通常在文件的开头使用,且声明必须在一行中,如果要换行就需要使用反斜杠\折行。

2. #define定义宏

2.1 无参宏

前面说过,#define宏可以定义常量,执行简单的文本替换操作,基本形式为:#define 宏名称 替换的值。它不是语句,所以后面不需要加分号,这样一条替换的规则,就被称为“宏”。

#define PI 3.14
#define MAX 10
#define MIN 0

上面示例中定义了三个宏,预处理程序会把源程序中的PI、MAX、MIN全都替换成对应的值3.14、10、0,宏名称遵循变量的命名规则,且不能有空格,一般以大写的形式出现;宏就是简单的文本替换,替换的值和指定的值一模一样,因此不受任何类型的限制。

通常#define指令都定义到一行,如果有多行,可以使用反斜杠“\”来换行。

#define STR "abcdefghigklmn,opq\
rstuvwxyz"

#define命令还支持多个宏包含替换,下面示例中的MAX2会被替换成100 * 100。

#define MAX 100
#define MAX2 MAX * MAX

2.2 带参宏

#define定义宏时,还可以接受一个或多个参数,与函数的参数写法类似。宏定义的参数是形式参数,宏替换的参数是实际参数,所以在进行替换的时候,不仅要宏展开,还要替换相应的参数。

//定义带参宏,注意宏名和参数括号之间不能有空格
#define MAX(A) A+A  

MAX(10);//宏替换成10+10

宏的参数列表也可以是空的,但是括号还是要写,主要用于调用函数。

#define PRINTF() printf("test")

和无参宏一样,带参宏也是支持使用反斜杠\来换行处理,还可以使用更大括号{}来创建局部作用域。

#define TEST(a,b){\
   printf("%d\n",a * b);
}

2.3 可变参宏

宏定义的参数的数量可以是不固定的,即可变参数的宏,就是不确定数量的参数。

#define X(a,b,...) a + b,__VA_ARGS__
//使用X宏
X(1,2,"test",10)
//宏展开后
1+2,"test",10

上面的示例中定义了一个可变参数的宏,前面有两个固定的参数a和b,后面可变参数使用来表示,后面的替换文本中,__VA_ARGS__表示多余的参数,注意只能放在最后。

2.4 #undef取消宏

#undef指令用来取消一个#define宏的定义。

#define MAX 100
#undef MAX  //取消MAX的宏定义

3. #include

#include是文件包含指令,用于将对应的头文件(.h)引入到当前文件中,有两种形式。

第一种是使用尖括号<文件名>,表示引入的是系统提供的标准库头文件,且不需要写路径。

#include <stdio.h> //引入标准库文件

第二种是使用双引号“文件名”,表示引入的是程序员自己定义的头文件,需要指定相对目录路径。

#include "test.h" //当前目录
#include "/pro/test.h"//在其他目录

4. #if、#else、#elif、#endif

预处理程序中还可以支持条件编译,#if指令集合表示条件判断,和if…else语句类似,当#if满足条件时,就会编译内部所定义的内容,否则就不会被编译。

#if 0
  int a = 5;//不满足条件
#endif

上面的示例中,#if 0表示条件不成立,所以会跳过这条语句,不会被编译。这一点和if语句很类似,后面可以跟表达式,通过判断表达式的结果来确定执行,为真就编译,为假就忽略。#endif指令用于结束一个#if指令的定义。它和#if指令是一一对应的。

#if…#endif之间还可以加入#else指令,用于处理#if指令条件不满足的情况。

#if 0
  int a = 5;//不满足条件
#else
  int a = 10;
#endif

#if 0不满足条件,就会执行#else指令里面的语句。

如果有多种情况需要判断时,就需要使用到#elif指令,相当于else if语句。

#define V 5

#if V == 1
  printf("V等于1");
#elif V == 5
  printf("V等于5");
#else
  printf("V是未知的");
#endif

5. #ifdef、#endif

#ifdef…#endif指令用于判断某个宏是否定义了,通常用于判断某个头文件是否被重复引入。

#ifdef X
  printf("X已经定义了\n");
#endif

如果宏X已经定义过,就会执行#ifdef指令里面的语句,否则会忽略。

#ifdef相当于#if指令的子集,它也是可以和#else指令结合使用的。

#ifdef X
  printf("X已经定义了\n");
#else
  printf("X没有被定义\n");
#endif

如果宏X没有被定义,则会执行#else指令中的语句。

6. #ifndef、#endif

#ifndef…#endif指令用于判断某个宏没有定义,它与#ifdef…#endif指令是对立的。

#ifndef X
  printf("X没有定义\n");
#endif

上面的示例中,如果宏X没有定义,则会执行#ifndef指令里面的语句,否则会忽略。

7. 预定义宏

C语言中提供了一些预定义的宏,可以直接使用但不能修改。

  • _DATE_:当前编译日期,格式为“MMM DD YYYY”的字符串;
  • _TIME_:当前编译时间,格式为“HH:MM:SS”的字符串;
  • _FILE_:当前文件名,也是一个字符串;
  • _LINE_:当前行号,以一个十进制常量表示;
  • _STDC_:定义为1,表示当前的编译器定义为标准C;
  • __STDC_VERSION__:编译器当前所使用的版本,格式为“yyyymmL”的整型常量。

8. 其他

8.1 #运算符

#运算符通常用于将宏定义替换文本的参数转换为字符串形式,只能用于带参数的宏。

#define MAX(a) #a  //参数前加#运算符
printf("%s\n",MAX(100));//输出字符串

上面示例中的MAX(100)展开后被替换成100,参数前加上#运算符就输出字符串,否则输出的是整数。

8.2 ##运算符

##运算符将宏的两个参数进行合并为一个标记符,通常用于生成多个变量名。

#define MAX(b) a##b

//声明多个变量
int MAX(1),MAX(2),MAX(3),MAX(4),MAX(5);//输出int a1,a2,a3,a4,a5;

8.3 #line指令

#line指令用于定义文件中的行号,可以覆盖掉预定义宏中_LINE_。

#line 100 //重置行号为100

上面的示例中将行号重定义为100,它是一个起始值,就是从下一行开始递增行号。

#line指令除了重定义行号以外,还可以改变文件名称。

#line 100 "test.h"

8.4 #error指令

#error指令用于程序在编译阶段输出错误,终止程序编译。

#define MAX 100
#ifndef MAX
#error undefined
#endif

上面的示例中,如果MAX宏未定义,则会进入#ifndef指令执行#error指令中的内容,并停止编译。

有错误的地方、需要补充的知识欢迎评论区发言、指正。

觉得有帮助可以赞赏本文哦~万分感谢!
文章:C语言教程(十四)预处理
作者:沛旗
链接:https://www.peiqiblog.com/article/2986/
版权声明::本博客站点所有文章除特别声明外,均采用 CC BY-NC-SA 4.0协议
转载请注明文章地址及作者哦~
暂无评论

发送评论(禁止发表一切违反法律法规的敏感言论) 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇