C语言预处理指令

本文详细介绍了C语言的预处理指令,包括预处理指令的种类、条件并入、源文件并入、宏替换及其作用域、行控制以及其他指令。重点讲解了宏替换的实参替换、##运算符和#define的作用域。适合初学者了解C语言预处理的全面知识。

系列文章目录

  1. C语言综述1
  2. C语言字符集2
  3. C语言词法元素3
  4. C语言表达式4
  5. C语言语句5
  6. C语言声明6
  7. C语言预处理指令7
  8. C语言头文件8


前言

蓝色问号代表个人理解   绿色代表来源   红色问号代表尚有疑问

为什么要读标准?因为全面、权威,所有答案都在标准里面!
哪些人适合浏览本系列文章?不清楚C语言程序的组成,以及每个组成部分的详细内容
持续更新,码字不易,求点赞收藏


1、预处理指令

预处理指令中预处理标记之间(从引入#预处理标记之后到终止新行字符之前)出现的唯一空白字符是空格和水平制表符(包括在翻译阶段3中替换注释的空格)

在这里插入图片描述

2、条件并入

  1. “#if 常量表达式 新行 可选的程序组”
  2. “#elif 常量表达式 新行 可选的程序组”
  3. “#ifdef 标识符 新行 可选的程序组”
  4. “#ifndef 标识符 新行 任选的程序组”
  5. “defined 标识符”、“defined (标识符)”、 “!defined 标识符”、"!defined (标识符)"也可替换前述常量表达式
#include <bits/stdc++.h>
using namespace std;

#define a 1			//成功输出b的值
#if defined(a)
    #define b 100
#endif
int main()
{
    cout << b;
    return 0;
}

3、源文件并入

#include指示应标识一个可被实现处理的头文件或源文件

  1. #include<头文件名序列>新行,在实现定义的位置搜索序列相同的文件
  2. #include"文件名字符序列"新行,搜索方式是实现定义的,搜索失败按<>方式处理
  3. #include 预处理token 新行,预处理token是和""还是<>组合是实现定义的
  4. 在分隔符内的外部源文件名:一个或多个字母,后跟句点(.)和单个字母
//test.h
int b = 100;
//test1.cpp
#include <bits/stdc++.h>
#define a "test.h"
#include a
using namespace std;
extern int b;
int main()
{
    cout << b;	//成功输出100
    return 0;
}

4、宏替换

  1. #define 标识符 替换表 新行

  2. #define 标识符 左括号 可选的标识符表 右括号 替换表 新行

  3. #undef

  4. 当且仅当两个替换列表中的预处理标记具有相同的数目、顺序、拼写和空白类符分隔(其中所有空白类符分隔被视为相同)时,两个替换列表是相同的

  5. 不用左括号的宏即类似对象的宏,可再重新定义,只要第二个定义是类似对象的定义,且替换表相同

  6. 使用左括号的宏即类似函数的宏,可再重新定义,只要第二个定义是类似函数的定义,且形参数目和拼写相同

  7. 类似函数的宏调用的实参数目应与形参数目一致,且应存在一个终止该调用的预处理单词 ‘)’,且其中的形参标识符应该使唯一声明的

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define RAND (rand() % 10)     //宏只是文本替换

#define ADD(a, b)  (a + b)      //带参数的宏

#define N 100
#define COUT printf("%d", N)   //不能递归调用宏

int main(int argc,char *argv[]){
    srand((unsigned) time(NULL));

    for(int i = 0; i < 10; i++ )
        printf("%d\n", RAND);
    
    COUT;
    printf("\n%d", ADD(5, 6));
    return 0;
}
4
3
9
2
7
7
1
6
8
7	//随机函数正常工作
100
11

4.1、实参替换

#算符
对于类似函数的宏,替换列表中的每个#预处理标记后面都应跟随一个参数,将实参字符替换到形参的相对位置

#include <bits/stdc++.h>
using namespace std;
#define b(c,a) c#a
int main()
{
    int buf = 100;					//输出
    cout << 1 << endl;				//1
    b(cout << ,buf << endl);		//	buf << endl
    cout << endl << 2 << endl;		//2
    return 0;
}

##算符
##预处理标记不得出现在任何形式宏定义的替换列表的开头或结尾,将实参含类型替换到形参

#include <bits/stdc++.h>
using namespace std;
#define b(c,a) c##a
int main()
{
    int buf = 100;					//输出
    cout << 1 << endl;				//1
    cout << b(100, 200);			//111311
    cout << endl << 2 << endl;		//2
    return 0;
}

4.2、重新扫描

代替完替换表的所有形参后,对结果所得预处理token和余下的token再重新扫描,若结果所得的预处理token中发现要替换的宏名,则不替换它,而且任何嵌套的替换遇到所要替换的宏名也不替换,这也是为什么宏名不可递归

4.3、宏定义作用域

直至遇到#undef或翻译单位末尾为止

5、行控制

  1. #line 数字序列 新行,设置行号
  2. #line 数字序列"字符串字面值" 新行,设置行号,并将源文件的假定名称更改为字符串文字的内容
  3. #line 预处理token 新行,此形式也允许,但宏替换后需与前两种形式的一种匹配
#include <bits/stdc++.h>
using namespace std;
#line 100

int main()
{
    cout << __LINE__ << endl;		//103
    cout << __LINE__;				//104
    return 0;
}

6、其他指令

出错处理指令
#error 可选的预处理token 新行 ,产生一个诊断消息,该信息包含指定的token序列

编译指令
#pragma 可选的预处理token 新行, 使实现按一种实现定义的方式动作,实现不能识别的编译指令将被忽略

空指令
#新行, 无作用

7、预定义的宏名

  1. _LINE_当前源行的行号(十进制常量)

  2. _FILE_假设的源文件名(字符串字面值)

  3. _DATE_翻译源文件的日期(格式为Mmm dd yyyy的字符串字面值,其中月份的名称与asctime函数生成的名称相同,如果值小于10,则dd的第一个字符为空格字符)如果翻译日期不可用,则应提供实施定义的有效日期

  4. _TIME_源文件的翻译时间(格式为hh:mm:ss的字符串字面值,与asctime函数生成的时间相同)。如果翻译时间不可用,则应提供实施定义的有效时间

  5. _STDC_十进制常数1,用以指示是一个符合标准的实现

  6. 除_LINE_和_FILE_外,预定义宏值不变

  7. 所有宏名不可再定义,且以一个下划线开始后跟大写字母或第二个下划线









以上纯属个人观点,欢迎大佬批评指正
  1. https://blog.youkuaiyun.com/init33/article/details/121258745 ↩︎

  2. https://blog.youkuaiyun.com/init33/article/details/121318734 ↩︎

  3. https://blog.youkuaiyun.com/init33/article/details/121319873 ↩︎

  4. https://blog.youkuaiyun.com/init33/article/details/121323883 ↩︎

  5. https://blog.youkuaiyun.com/init33/article/details/121323943 ↩︎

  6. https://blog.youkuaiyun.com/init33/article/details/121323932 ↩︎

  7. https://blog.youkuaiyun.com/init33/article/details/121323958 ↩︎

  8. https://editor.youkuaiyun.com/md/?articleId=121323994 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值