赞
踩
「今天是学习C语言第 32 天」
当你选择了一种语言,意味着你还选择了一组技术、一个社区。——Joshua Bloch
# 预处理
C语言源程序先经过预处理器进行预处理,之后经过编译器编译成二进制可执行代码执行。一般编译器套件、集成开发工具都将两种工具集成,预处理过程和编译过程一并处理。
C语言预处理是通过预处理指令实现,每个预处理指令以#符号开头,以行为单位,实现编译前的准备工作,例如文件条件引入、宏替换和条件编译。
# 预处理指令
C语言提供以下预处理指令,预处理指令必须以#开头,#符号必须是当前行的第一个非空白字符。预处理指令以一行作为处理单位,每行预处理指令是有多个预处理单词组成,单词之间使用空格或横向制表符分割。
预处理指令包括:
- #include:包含一个指定的源文件
- #define :定义一个宏
- #undef :取消已定义的宏
- 条件编译:#if #ifdef #ifndef #elif #else #endif
- #line :产生下一代码行号和源文件名称
- #error :产生一个诊断错误信息
- #pragma :编译指示,预处理器实现自定义的编译动作
- # :空指示,不起作用
# 文件包含
编译前引入特定的文件内容到当前的源代码文件中一起编译,主要用来引入头文件或其他源代码文件。三种形式:
第一种:
#include :一般从系统路径位置寻找引入的头文件。
第二种:
#include "文件名":一般是先在用户定义的路径寻找该文件,如果找不到再去系统路径寻找。
第三种:
#include 任意的预处理单词
该形式下的预处理单词也按照普通正文进行处理,处理完成以后,应和前两种之一匹配,再进行处理。
例如:
#include
#include "mystdio.h"
#define MYFILE "mystdio.h"
#include MYFILE
# 宏替换
宏(英文:Macro),根据一系列预定义的规则替换一定的文本模式,作用是将一个简单的小命令或动作转化为一系列指令,C语言中的宏的作用就是在宏出现的位置展开替换的文本。
语法:
#define 宏名 替换文本 :简单替换
#define 宏名(参数) 替换文本 :带参数的宏,类似函数调用
例如:
#define MAX_LEN 100
char str[MAX_LEN];
定义常量,使用宏定义字符数组最大长度,出现MAX_LEN全部替换成100,当需要修改数组长度时,只需要修改宏定义即可。
#define MAX_LEN 100
#undef MAX_LEN
char str2[MAX_LEN];
取消MAX_LEN宏定义,在#undef命令之后,就不能使用该宏,否则编译出错。
#define SUM(a, b) (a+b)
int s = SUM(1,2);
double d = SUM(100.01,200.01)
类似函数,使用宏定义计算参数a和b的和。
# 条件编译
根据条件例如不同硬件平台,选择不同的代码进行编译,方便程序移植和跨平台。
if条件有三种形式:
#if 常量表达式
#ifdef 宏名称
#ifndef 宏名称
根据if条件值,当值为0时,忽略和不编译后面代码文本。
注:#if后面必须是常量表达式,不能是函数调用和变量。
其中#if可包含以下条件:
#if defined 宏名称
#if defined (宏名称)
#ifdef 等价于 #if defined
#if ! defined 等价于 #ifndef
else条件三种形式:
#elif:#else和#if的结合,后面常量表达式
#else:与#if配合使用
#endif:结束#if或#else条件块
例如:
#ifndef MYHEADER_H
#define MYHEADER_H "myheader.h"
// 头文件内容
#endif
避免重复引入同一个文件多次,可以在被引入的头文件开头加入添加编译。
例如:不同硬件平台使用数字代替,x86=0,x64=1,arm=2。
#define X86 0
#define X64 1
#define ARM 2
#define ARCH 0
#if ARCH==0
#include "x86.h"
#elif ARCH==1
#include "x64.h"
#elif ARCH==2
#include "arm.h"
#else
#include "others.h"
#endif
或者:
#define DEBUG
#ifdef DEBUG
// 执行调试模式下的代码
#else
// 执行非调试模式下的代码
#endif
等价于:
#define DEBUG
#if defined DEBUG
// 执行调试模式下的代码
#else
// 执行非调试模式下的代码
#endif
# 行控制
预处理指令#line 用来控制编译器编译时警告和错误信息的行号和文件名。
两种形式:
1.#line 整数n
设置当前#line所在行的行号是整数n,后面的代码行均从此整数计数。
例如:
#include int main(){int *p = NULL;#line 30*p = 0return 0;}
编译出错:提示是31行出错,*p=0 末尾缺少分号,出错的文件名默认是当前文件名。
2.# line 整数n 文件名称
设置当前#line所在行的行号和当前文件名。
#include int main(){int *p = NULL;#line 30 "mytest.c"*p = 0return 0;}
编译出错:提示是mytest.c文件的31行出错,*p=0 末尾缺少分号。
# 出错处理指示
预处理指令#error用来控制编译器停止编译,显示特定的出错信息。
例如:
#include int main(){#error "test error"return 0;}
编译出错:显示 "test error"
# 编译指示
预处理指令#pragma,各种编译器实现自定义预处理功能,用于扩展,例如禁用编译器的一些警告信息,拓展一些编译功能,标准没有定义具体的指令,需要根据不同编译器文档使用。
# 系统预定义的宏名
预定义的宏以两个下划线开头__。
__LINE__ 当前源代码的行号
__FILE__ 当前的源代码文件名称
__DATE__ 编译日期,格式是Mmm dd yyyy
__TIME__ 编译时间,格式是hh:mm:ss
__STDC__ 表示当前编译器是否符合标准,1表示符合标准
例如:
#include int main(){printf("%d\n", __LINE__);printf("%s\n", __FILE__);printf("%s\n", __DATE__);printf("%s\n", __TIME__);printf("%d\n", __STDC__);return 0;}
输出:4E:\dev\test.cApr 2 202020:35:251
# 有关宏中的#和##运算符
宏中的#运算符,将宏参数字符串常量化,具体是将#和跟在其后的参数转换成字符串,自动加入双引号和转义特殊字符。
例如:
#include #define TEST(s) "012345"#s"789\n"int main(void){printf(TEST(6));printf(TEST("6"));return 0;}
输出:0123456789012345"6"789
##运算符将多个宏参数的值直接连接起来(不转换为字符串),##出现的两个宏参数中间,不能出现替换文本的开头和末尾。
例如:
#include #define TEST(s1,s2,s3) s1##s2##s3int main(void){printf("%d\n",TEST(1,2,3));return 0;}
输出:123
---------- End ----------
往期精彩推荐:
「喜欢C请赏个 赞 点击右下角 在看」
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。