1、预处理指令
预处理指令是以#
号开头的代码行,#
号必须是该行除了任何空白字符外的第一个字符。#
后是指令关键字,在关键字和 #
号之间允许存在任意个数的空白字符,整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。
常用的预处理指令:
指令 | 描述 |
#define | 定义宏 |
#include | 包含一个源代码文件 |
#undef | 取消已定义的宏 |
#ifdef | 如果宏已经定义,则返回真 |
#ifndef | 如果宏没有定义,则返回真 |
#if | 如果给定条件为真,则编译下面代码 |
#else | #if 的替代方案 |
#elif | 如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码 |
#endif | 结束一个 #if……#else 条件编译块 |
#error | 当遇到标准错误时,输出错误消息 |
#pragma | 使用标准化方法,向编译器发布特殊的命令到编译器中 |
2、宏定义(#define)
宏定义又称为宏代换、宏替换,简称“宏”。
1) 不带参数的宏定义
格式如下:
#define 标识符 文本
其中的标识符就是所谓的符号常量,也称为“宏名”。
例如,
#define PI 3.1415926
注意:
- 宏名一般用大写
- 使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义
- 可以用
#undef
命令终止宏定义的作用域 - 宏定义可以嵌套
2)带参数的宏
除了一般的字符串替换,还要做参数代换。
格式如下:
#define 宏名(参数表) 文本
例如,
#define S(a,b) a*b
将area=S(3,2);
进行宏替换,第一步被换为area=a*b;
,第二步被换为area=3*2;
注意:有时宏替换后和我们预期的结果不一样需要注意一下,宏替换只是简单的替换。
3、文件包含
C语言程序文件中一个文件包含另一个文件的内容。
格式如下:
#include "文件名"
或
#include <文件名>
相关文档: C语言中#include <filename> 和 #include "filename"的区别
编译时以包含处理以后的文件为编译单位,被包含的文件是源文件的一部分。
编译以后只得到一个目标文件.obj
被包含的文件又被称为“标题文件”或“头部文件”、“头文件”,并且常用.h作扩展名。
修改头文件后所有包含该文件的文件都要重新编译
头文件的内容除了函数原型和宏定义外,还可以有结构体定义,全局变量定义:
1)一个#include命令指定一个头文件;
2)文件1包含文件2,文件2用到文件3,则文件3的包含命令#include应放在文件1的头部第一行;
3)包含可以嵌套;
4)<文件名>称为标准方式,系统到头文件目录查找文件,"文件名"则先在当前目录查找,而后到头文件目录查找;
5)被包含文件中的静态全局变量不用在包含文件中声明。
4、 条件编译
有些语句在条件满足时才编译。例如,不同平台使用不同的代码实现,需要针对平台来编译。
格式:
#ifdef 标识符
程序段1
#else
程序段2
#endif
或者
#ifdef
程序段1
#endif
注意:
上面格式中,当标识符已经定义时,程序段1才参加编译。
或者
#ifndef 标识符
#define 标识1
程序段1
#endif
注意:
上面格式中,如果标识符没有被定义,则重定义标识1,且执行程序段1。
或者
#if 表达式1
程序段1
#elif 表达式2
程序段2
……
#elif 表达式n
程序段n
#else
程序段n+1
#endif
注意:
上面格式中,当表达式1
成立时,编译程序段1
,当不成立时,编译程序段2
。
使用条件编译可以使目标程序变小,运行时间变短。
5、编译时产生错误
#error
用于在预处理时产生一个错误信息,通常用于检查条件不满足的情况,以中止编译。
格式:
#error "错误信息"
使用示例:
#ifdef VERSION
#if VERSION < 2
#error "VERSION is too low. Must be at least 2."
#endif
#endif
6、编译器指令
#pragma
是一种编译器特定的指令,允许编译器执行特殊的操作。不同编译器支持的 #pragma
选项可能不同。
格式:
#pragma 指令
使用示例:
#pragma warning(disable : 4996) // 禁用特定的编译器警告(在某些编译器中)
7、指定行号
#line
用于更改行号或文件名的显示。它可以在调试或生成错误报告时调整行号信息。
格式:
#line 行号 ["文件名"]
使用示例:
#line 200 "myfile.c"
printf("This is line 200 in myfile.c\n");
8、宏中的拼接与字符串化
##
运算符用于在宏定义中连接两个标识符,#
运算符用于将宏参数转化为字符串。
#define CONCAT(a, b) a##b
int CONCAT(num, 1) = 100; // 等价于 int num1 = 100;
#define TO_STRING(x) #x
printf(TO_STRING(Hello World)); // 输出:"Hello World"
9、内置宏
__FILE__
当前文件名,__LINE__
当前行号。
printf("Error in file %s on line %d\n", __FILE__, __LINE__);
注意:C语言中的预处理命令提供了一种在编译之前对代码进行处理的方式,帮助程序员定义宏、条件编译、包含文件、生成错误信息等。通过合理使用这些指令,可以提高代码的灵活性和可维护性。