【C语言重点难点精讲】C语言预处理
文章目录
- 一:C/C++程序程序编译过程
- (1)预处理
- (2)编译
- (3)汇编
- (4)链接
- 二:宏定义
- (1)数值宏常量
- (2)字符串宏常量
- (3)使用宏充当注释
- (4)使用宏充当表达式
- 三:宏其他
- 四:条件编译
- (1)#ifdef和#ifndef
- (2)#if
- (3)文件包含
一:C/C++程序程序编译过程
(1)预处理
- 预处理主要包括宏定义,文件包含,条件编译,去注释
- 输入
gcc -E hello.c -o hello.i
,其中选项E作用是让gcc在预处理后停止编译
(2)编译
- 此阶段,gcc检查代码的规范性,是否具有语法错误
- 输入
gcc -S hello.i -o hello.s
,即可将预处理里的结果继续继续编译
(3)汇编
- 编译阶段无误后,进入汇编,将“.s”文件转化为“.o”二进制文件
- 输入
gcc -c hello.s -o hello.o
,即可将编译停止在此阶段
(打开二进制文件使用od
命令)
(4)链接
- 此阶段,将目标文件与系统库进行链接生成可执行文件。
- 输入
gcc hello.o -o hello
,则完成编译
选项 | 描述 |
---|---|
-E | 进行预处理,不进行编译,汇编和链接 |
-S | 进行编译,不进行汇编和链接 |
-c | 进行汇编,不进行链接 |
-o | 链接 |
static | 采用静态链接 |
-g | 生成调试信息 |
-shared | 使用动态库 |
-O0 | 无优化 |
-O1 | 默认优化级别 |
-O3 | 优化最高 |
-w | 不生成警告信息 |
-Wall | 生成所有警告信息 |
二:宏定义
(1)数值宏常量
略
(2)字符串宏常量
略
(3)使用宏充当注释
先去掉注释,再进行宏替换
(4)使用宏充当表达式
#define SUM(X) (X)+(X)int main()
{printf("%d\n", SUM(10));return 0;
}
需要注意使用宏充当多条语句时有可能出现一些潜在的问题,比如下面这个宏有两条语句,但是在if
后面如果直接跟上宏而没有带花括号就会出现问题
#define INT_VAL(a,b) a=0;b=0
如果需要宏替换大块语句,可以使用do-while(0)
结构
#define GIVE_VALUE(a,b) do{a=0;b=0;}while(0)int main()
{int x = 10;int y = 20;int flag = 0;scanf("%d", &flag);printf("before:%d,%d\n", x,y);if (flag)GIVE_VALUE(x, y);elsex = 10, y = 20;printf("after:%d,%d\n", x, y);}
三:宏其他
第一: 宏定义在文件的任何位置都可以,只要是在你使用这个宏之前定义就可以
void show()
{#define M 10printf("show:%d\n", M);
}
int main()
{show();printf("main:%d\n", M);return 0;}
第二 可以使用#undef
来结束宏的作用
int main()
{#define M 10//从这里开始printf("main:%d\n", M);printf("main:%d\n", M);printf("main:%d\n", M);
#undef M//到这里结束printf("main:%d\n", M);//错误return 0;}
第三:有如下宏定义
#define foo(4+foo)
按照一般理解 + foo)会展开成(4 + (4 + foo)),然后一直展开下去,直至内存耗尽。但是,预处理器采取的策略是只展开一次 。也就是说,foo只会展开成(4 + foo),而展开之后foo的含义就要根据上下文来确定了。
对于以下的交叉引用,宏体也只会展开一次
#define x(4+y)
#define y(2+x)
其中x展开成(4+y)->(4+(2*x)),y展开成(2 * x) -> (2 * (4 + y))。
#include <stdio.h>
#define N 2
#define M N + 1
#define NUM (M + 1) * M / 2
main() { printf("%d\n", NUM); }
宏只是字符串替换,并没有计算能力,所以最后的结果是(2+1+1)*2+1/2
四:条件编译
(1)#ifdef和#ifndef
ifdef
:判定宏是否被定义,宏为真假没有关系,倾向于要定义,ifndef
:判定宏是否没有定义,宏为真假没有关系,倾向于不要定义
下面的例子中没有定义PRINT
,所以代码只会保留#else
这一部分,代码在预处理时直接被裁掉
int main()
{#ifdef PRINT//实际未定义printf("hello\n");
#elseprintf("no print\n");
#endifreturn 0;
}
如果PRINT
被定义了,然后换成ifndef
,效果也是一样的
#define PRINT//宏被定义
int main()
{#ifndef PRINT//如果没有定义printf("hello\n");
#elseprintf("no print\n");
#endifprintf("continue\n");return 0;
}
(2)#if
#if
:判定是否存在,以及是否为真,倾向于存在且为真
如下宏PRINT
,被定义了但是为0,因此会输出#else
里面内容
# define PRINT 0//定义了但是为假int main()
{#if PRINTprintf("hello\n");
#else PRINTprintf("other");
#endifreturn 0;
}
#if
可以进行多分支控制
#define HELLO 2//注意这里使用的是==,像!=,<,>等可以使用
int main()
{#if HELLO==1printf("hello1\n");
#elif HELLO==2printf("hello2\n");
#elif HELLO==3printf("hello3\n");
#elseprintf("other\n");
#endifreturn 0;
}
如果要判断多个宏,可以这样进行
#define Condition1 1
#define Condition2 0int main()
{#if Condition1 && Condition2printf("all\n");
#elseprintf("other\n");
#endifreturn 0;
}
(3)文件包含
有一个头文件test.h
,为了防止其被重复包含,我们通常的做法就是,在该文件内写上这样的语句。现在看来效果很明显,在第一次包含时#define会被立即被定义,第n次包含时由于_TEST_H被定义了,所以就不会执行
#ifndef _TEST_H
#define _TEST_H#endif // !_TEST_H
- 其实头文件在展开时,本质就是将其内容经过一些处理后拷贝到了目标源文件
【C语言重点难点精讲】C语言预处理相关推荐
- 【C语言重点难点精讲】C语言指针
文章目录 一:指针入门 二:数组入门 (1)数组的内存空间布局 (2)区分&arr[0]和&arr 三:指针和数组的关系 (1)以指针的形式访问和以数组形式访问 (2)为什么C语言要这 ...
- 【C语言重点难点精讲】关键字精讲
必读: C语言关键字是一个非常重要的话题,因为它能在相当的程度上将C语言的核心内容串联起来,起到一种提纲挈领的效果 下面的内容重点提及的是相应关键字特别值得注意的地方,这些地方是我们经常忽略的,而且考 ...
- 【C语言重点难点精讲】C语言文件
文章目录 一:文件相关概念 (1)什么是文件 (2)文件名 (3)文件类型 二:文件指针 三:文件的打开和关闭 四:文件的顺序读写 (1)写 (2)读 五:文件的随机读取 (1)fseek (2)ft ...
- 【C语言重点难点精讲】C语言内存管理
文章目录 一:相关动态内存函数 (1)malloc和free (2)calloc (3)realloc 二:进程地址空间 三:常见内存错误 C语言内存管理其实是一个很糟糕的话题,很烦这个,但是没有办法 ...
- 【C语言重点难点精讲】C语言中的重要符号
文章目录 一:续接符和转义符 (1)续接符 (2)转义字符 二:单引号和双引号 三:逻辑运算符 四:位运算 四:左移右移 五:前置++和后置++ 六:优先级 一:续接符和转义符 (1)续接符 如果一行 ...
- r语言 新增一列数字类型_R语言实战之R语言基础语法精讲(一)
R是用于统计分析.绘图的语言和操作环境.R是属于GNU系统的一个自由.免费.源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具.在学习R数据科学之前,我们首先要对R语言的基础语法有一个良好的了 ...
- c语言程序设计冲刺串讲,C语言程序设计冲刺串讲.ppt
C语言程序设计冲刺串讲.ppt C语言程序设计,冲刺串讲,温馨提示,离考试只有不足4周的时间了,我们的好多学员对自己没有信心,对此我建议大家不要放弃最后的一线希望,奇迹总是出现在最后.为此我们一定要加 ...
- R语言实战应用精讲50篇(十六)--如何实现文字云可视化
前言 本文跟大家分享R语言信息可视化--文字云. R语言可以轻松处理信息可视化,并且很早就有专用的信息可视化包--WordCloud. 以下是我为大家准备的几个精品专栏,喜欢的小伙伴可自行订阅,你的支 ...
- R语言实战应用精讲50篇(十八)-R语言实现分词、词频与词云案例解析
前言 我真的超爱R语言,原因之一就是R有许多已经写好."开箱即用"的程序包可以直接拿来用:要知道,程序包减少了多少工作量.当然,其他语言也有类似的包,但是貌似没那么多.没那么细.这 ...
最新文章
- activemq 控制台怎么看生产信息_Jmeter中间件处理-ActiveMQ
- 张正友标定法 【计算机视觉学习笔记--双目视觉几何框架系列】
- java 常量接口_java接口定义常量研究
- 20145209预备作业01
- mysql数据库内存分配_MySQL OOM 系列一 Linux内存分配
- Bailian3258 兔子产子【递推+打表】
- 23种设计模式(三)组件协作之策略模式
- python前端和后端_python是用于前端还是后端开发
- H.264(MPEG)-4AVC
- 【oracle】Linux环境安装Oracle客户端
- ubuntu 20.04 | 美化主题、图标、光标、壁纸、登录背景
- Linux中使用 if 、for、while等循环来写脚本
- 计算机辅助模具设计实训心得6,模具设计实训心得体会3篇
- origin图上显示数据标签_Origin中如何将曲线上的数据显示出来?
- 分享教程,制作Srt字幕最简单的方法
- nginx+rtmp(或http-flv)+ffmpeg搭建流媒体视频直播服务器
- Android系统WebView无法安装,Android系统进程无法加载WebView
- lisp语言cond和if套用_方案 – if和cond之间的区别?
- 安装群晖系统入门图文教程
- c语言十全十美游戏规则,十全十美游戏
热门文章
- 第十七节:ES6新增的Map和WeakMap 又是什么东西?
- 苹果小圆点怎么弄出来_原来苹果手机轻点2下屏幕就能截图,以前还不知道,太方便了...
- 从一套表达和通路数据学习常见的绘图展示方式和报错处理
- 简单几步,教你在mac电脑上轻松启用悬停文本!
- 1.10 编程基础之简单排序 04 奖学金 7分 python
- 第2课 贝贝的图形(vhist)-2019-07-11《聪明人的游戏-提高篇》
- java锁的级别_Java锁的那些事儿之JDK锁(ReentrantLock)
- sql配置管理器服务是空的_PostgreSQL 12 安装和配置
- CentOS8 安装图形界面后,怎么转换为命令行界面
- jquery复选框组清空选中的值_防火墙基本配置:配置策略组