超详细的C进阶教程!(七)C语言预处理

作者的码云地址:https://gitee.com/dongtiao-xiewei
后续作者会更新力扣的每日一题系列,原代码会全部上传码云,推荐关注哦,笔芯~

还像更深入地了解c语言?快来订阅作者的c语言进阶专栏!作者承诺本系列不会TJ!预计更新:指针,字符串处理,内存管理,结构体,预处理等等

感谢朋友们的支持,我们这个系列今天终于完结啦!

我们一直以来写的代码,本质其实都是以.c文件为后缀名的文本文件,例如我们随便以记事本形式点来一个.c后缀的文件

超详细的C进阶教程!(七)C语言预处理_第1张图片
点开我们看到,就是我们熟悉的代码样式

但这就有一个问题,这种文本文件是如何被计算机识别的呢?

其实计算机能够识别的就只有机器语言,也就是一串二进制代码,早期的程序员也是全用机器语言编程,后面为了避免麻烦,简化编程的过程,就产生了较为容易理解汇编语言,而汇编过程就是将汇编语言转化为机器语言

而为了解决平台的可移植性和通用性的问题,又产生了高级语言,例如c语言,basic语言等,而编译过程,可把高级语言转化为汇编语言

所以,现代计算机可分为以下几个层次

超详细的C进阶教程!(七)C语言预处理_第2张图片
我们的c代码若要生成一个可执行程序(二进制代码)需要进行以下几个步骤

超详细的C进阶教程!(七)C语言预处理_第3张图片
今天的章节我们重点介绍预处理环节

预处理环节将会进行以下工作

  1. 处理define定义好的标识符,宏等
  2. 去掉注释

我们可以先测试一下去掉注释

int main()
{
     
	printf("hello world!\n");//you can see me!
	return 0;
}

预处理后的结果:
超详细的C进阶教程!(七)C语言预处理_第4张图片

注:由于VS编译器查看预处理后的代码比较困难,所以本章节的代码我们使用linux平台测试

本节用到的linux指令:
touch test.c创建一个源文件
vim test.c 编写代码
gcc -E test.c -o test.i 将预处理后的代码保存在test.i中

好,坐稳扶好,我们正式开始喽!

目录

  • #define
    • #define定义标识符
    • #define定义宏
  • 条件编译
    • #ifdef
    • ifndef
    • #if

#define

#define定义标识符

通用格式:

#define name stuff

例子:

#define MAX 200
#define str struct

我们用这个定义标识符可以起到定义常量,重命名,同名替换等等

可以在linux上简单测试一下

#define MAX 200
#define reg register

int main()
{
     
	reg int a=MAX;
	printf("%d\n",a);
	return 0;
}

超详细的C进阶教程!(七)C语言预处理_第5张图片

而代码也能跑的过去
超详细的C进阶教程!(七)C语言预处理_第6张图片

我们可以看到,预处理阶段就完成了简单替换

萌新最容易犯的错误:在定义完成后加上’’;’'

#define MAX 200;

虽然这个代码可能在有些情况不会出错,但替换下来就是这个结果

超详细的C进阶教程!(七)C语言预处理_第7张图片
看起来很奇怪,是吧!

#define定义宏

这是define的一个特殊机制,允许把参数替换在文本中

例子

#define DOUBLE(x) (x+x)

通用格式

#define name(list) stuff

宏的使用

超详细的C进阶教程!(七)C语言预处理_第8张图片

虽然是宏,但我们可以观察到,本质也是简单替换

超详细的C进阶教程!(七)C语言预处理_第9张图片

我们同样也可以定义以下的宏

#define SQUARE(x) x*x

但是注意,这个宏存在一个问题,假如我们要算这个表达式的结果

SQUARE(5+1)

我们期望结果当然是6的平方,也就是36

但是我们测试发现结果并不是36

在这里插入图片描述
结果居然是11!

我们可以打开test.i文件查看一下预处理后的代码

超详细的C进阶教程!(七)C语言预处理_第10张图片

我们可以发现,宏仅仅只是完成了简单替换,并没有考虑优先级的问题

这个其实就是根据替换后的算术优先级来计算结果

1*5=5+5+1=11

当然,为了避免算术优先级的问题,我们可以对代码做一点改进

#define SQUARE(x) ((x)*(x))

这样修改后,宏就会是相对独立的运算结果了

在这里插入图片描述

条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。

有以下条件编译指令

#ifdef,#ifndef,#if等等

注意,条件编译的末尾一定要加上#endif!

#ifdef

只有你编译了某个宏,代码才会被执行
比如我们在要调试一个代码的场景

超详细的C进阶教程!(七)C语言预处理_第11张图片

超详细的C进阶教程!(七)C语言预处理_第12张图片

这里显示了打印字符,如果我们把它注释掉,就不会显示

ifndef

同样还是上面的代码,但是却与上面功能相反

没有定义,才执行下列的程序

应用场景:头文件防止被重复包含

#ifndef __TEST_H__
#define __TEST_H__
//代码

#endif

#if

与分支语句的if相同,例如

超详细的C进阶教程!(七)C语言预处理_第13张图片

超详细的C进阶教程!(七)C语言预处理_第14张图片

你可能感兴趣的:(C语言进阶系列,c语言,c++,linux)