预定义宏
C程序编译的第一步是预处理,编译器调用预处理器对程序进行预处理(文件包含、展开宏等)预处理器有预定义一些特殊含义的宏,这些预定义宏常用于调试程序,所以又称调试宏。不同预处理器支持的预定义宏可能有所不同,但一般都支持以下五种:
预定义宏 | 含义 | 用法示例 |
__FILE__ | 所在文件的文件名 | printf("%s\n", __FILE__); |
__LINE__ | 所在语句的行数 | printf("%d\n", __LINE__); |
__FUNCTION__ | 所在函数的函数名 | printf("%s\n", __FUNCTION__); |
__DATE__ | 运行日期 | printf("%s\n", __DATE__); |
__TIME__ | 运行时间 | printf("%s\n", __TIME__); |
其中,__FUNCTION__可以简写为__func__,宏名前后各两条下划线。
# 和 ##
一、# 用于把参数转换为字符串,常用于输出变量名,如:
#define PINT(x) printf("%s = %d\n", #x, x)
#define PCHAR(x) printf("%s = %c\n", #x, x)
...
使用 PINT(x) 可以同时输出变量名和变量值
二、## 是一个连接符,把前后字符串连接起来,可以用于定义多个类似函数,如:
int flash_device_open();
int flash_device_close();
int flash_device_read();
int flash_device_write();
可以用如下方式定义:
#define FLASH(x) flash_device_ ## x
int FLASH(open)();
int FLASH(close)();
int FLASH(read)();
int FLASH(write)();
预处理命令
C语言预处理命令主要有三种:宏定义、文件包含、条件编译。
一、宏定义
1、注意定义运算时多加括号,以免由运算符优先级引发问题;
2、#undef 用于删除宏定义。
二、文件包含
注意如下使用方法,双引号可以按路径寻找自定义头文件:
#include "../my_include/file01.h"
三、条件编译
顾名思义,就是设定条件,条件成立才编译,有如下几种:
条件命令 | 条件 | 含义 | 用法示例 |
#if | 必须为常量或常量宏,不能用变量 | 如果常量或常量宏不为0,执行下面命令 | #define FLAG 1
#if FLAG ... |
#ifdef | 必须为宏名 | 如果定义了某个宏 | #define FLAG ... #undef FLAG ... #ifdef FLAG ... |
#ifndef | 必须为宏名 | 如果没有定义某个宏 | #ifndef FLAG ... |
三个命令都可以搭配 #else、#endif 使用。
除此之外:
1、比较有用的还有 #pragma 命令,非常好用,但比较复杂,可以参考相关文章学习,这里放一个示例:
#define FLAG
...
#ifdef FLAG
#pragma message("FLAG has been defined!")
#endif
当编译到这里的时候,会打印双引号中的文本,但要注意:该文本只会在编译时起作用,显示在编译输出窗口,程序运行时不会出现,所以不能用来取代printf。
2、与 #pragma message 作用相似的还有 #error 命令:
#define FLAG
...
#ifdef FLAG
#error "FLAG has been defined!"
#endif
当编译到此处时,编译会被停止,并打印文本信息。而 #pragma message 不会停止编译。
3、如果只是为了 确定某个宏在代码中某处 是否被打开 或 宏值是否为0,也可以用如下方法:
#define FLAG 1
...
#if FLAG
bgjqhg
#endif
在代码中随便添加一行无意义文本,如果 FLAG 不为0,编译会在这里出错,编译器会停止编译并报错。