0
点赞
收藏
分享

微信扫一扫

c语言最后预处理送给你

耳一文 2022-02-26 阅读 56

一篇思维导图送给大家(总结思维导图真的提升非常大);

目录

预处理

一些预定义符号

 #define定义标识符

#define定义宏

 #define的替换规则

带副作用的宏参数

 宏与函数对比

#undef

​ 

命令行定义

 条件编译

文件包含

头文件重复包含问题

头文件重复包含解决方案


预处理

一些预定义符号

__FILE__                          进行编译的源文件

__LINE__                          文件当前的行号

__DATE__                       文件被编译的日期

__TIME__                         文件被编译的时间

__STDC__                        如果编译器遵循ANSI C,其值为1,否则未定义

这些预定义符号就可以打印对应的内容,比如我们来举个例子

int main()
{
	printf("file:%s\n", __FILE__);//进行编译的源文件
	printf("line:%d\n", __LINE__);// 文件当前的行号
	printf("data:%s\n", __DATE__);// 文件被编译的日期
	printf("time:%s\n", __TIME__);// 文件被编译的时间
	return 0;
}

 #define定义标识符

语法:

#define  name (名字) stuff(这个名字要替换的内容)

这个#define在写项目时候是经常被我们用到#define可以定义一个名字,然后将这个名字替换成它所对应的值,在项目中使用#define可以大量减少修改代码次数,当我们想要修改值的时候,可以直接在#define所要替换的值修改即可。

#define M 10
int main()
{
	printf("%d\n", M);
	return 0;
}

  •  这里会有一个问题,#define后面要不要加分号呢?

答案是不要。为什么不要呢?

 看这个例子如果M后面加上分号,第一个条件里的内容就变成M;;又多了一个分号就会导致语法错误。

#define定义宏

什么是宏呢?宏就是可以将参数替换到文本中。

#define name( parament - list ) stuff

其中的 parament - list 是一个由逗号隔开的符号表,它们可能出现在 stuff 中。

注意:参数列表的左括号必须与 name 紧邻。

如果两者之间有任何空白存在,参数列表就会被解释为 stuff 的一部分

说这个可能大家都不太理解,我来用代码给大家举个例子。

#define MAX(x,y)  ((x)>(y)?(x):(y))
int main()
{
	int a = 10;
	int b = 20;
	printf("max = %d\n", MAX(a, b));
	return 0;
}

这里需要注意的是

还有一点要注意的是

#define DOUBLE(x,y) x*y
int main()
{
	int a = 2;
	int b = 3;
	printf("%d\n", DOUBLE(a + 2, b + 1));
	return 0;
}

 这里的答案是多少呢?难道是4*4=16么?

答案是错误的这里会将x,y替换变成,a+2*b+1  这里就会导致操作符优先级问题导致结果不是你想要的,解决办法是,当你害怕操作符优先级问题导致结果错误的时候,你就可以加上括号避免操作符优先级问题。

#define DOUBLE(x,y) (x)*(y)

我们改成这样就不会有问题了。

 #define的替换规则

在程序中扩展 #define 定义符号和宏时,需要涉及几个步骤。

1. 在调用宏时,首先对参数进行检查,看看是否包含任何由 #define 定义的符号。如果是,它们首先被替换。

2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。

3. 最后,再次对结果文件进行扫描,看看它是否包含任何由 #define 定义的符号。如果是,就重复上述处理过程。

#和##

#的作用是把一个宏参数变成对应的字符串

这里有一个例子

 这里我们可以发现不管printf里放入几个字符串,最后都会将他们转化成一个。好我们接下来看

printf("the value of b is %d\n", b);

我可不可以让双引号里的b改变呢?

当然可以这就需要用到#


#define PRINT(n) printf("the value of "#n" is %d\n", n)
int main()
{
	int a = 10;
	//printf("the value of a is %d\n", a);
	PRINT(a);
	//printf("the value of ""a"" is %d\n", a);

	int b = 20;
	//printf("the value of b is %d\n", b);
	PRINT(b);
	//printf("the value of ""b"" is %d\n", b);
	return 0;
}

这里宏中的#b是将原来的字以字符串的形式替换,也就是比如b 就会以”b”替换到文本中。

这里只有当字符串作为宏参数的时候才可以把字符串放在字符串中

##的作用是可以将两个符号合成一起

#define ADD(x,y)   x##y

int main()
{
	printf("%d\n", ADD(521,1314));
	return 0;
}

带副作用的宏参数

#define MAX(x,y)  ((x)>(y)?(x):(y))
int main()
{
	int x, y, z;
	x = 5;
	y = 8;
	z = MAX(x++, y++);
	printf("x=%d y=%d z=%d\n", x, y, z);
	return 0;
}

这个答案会是什么呢?

 宏与函数对比

我们拿两个数比较举例子

函数写法:

int get_max(int x, int y)
{
	return x > y ? x : y;
}
int main()
{
	int a = 10;
	int b = 20;
	int ret = get_max(a, b);
	return 0;
}

宏的写法:

#define MAX(x,y)  ((x)>(y)?(x):(y))
int main()
{
	int a = 10;
	int b = 20;

	printf("max = %d\n", MAX(a, b));
	return 0;
}

宏的缺点:

#undef

 

命令行定义

 条件编译

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

文件包含

终于到了最后一个,这个文件包含在高质量c/c++编程书中就出过两个关于头文件包含的问题,所以这块非常重要。

我们在进行头文件包含的时候,主要使用#include命令,这里有两种方式,一种是#include后面用双引号,一种是#include后面用<>.那两种是否有区别呢?

先说#include"   "

查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。 如果找不到就提示编译错误。

再说#include<>

查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。

那标准库文件也可以用include"",只不过他要查找两次更浪费时间,但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。

头文件重复包含问题

头文件重复包含解决方案

第一种是使用#pragma once

另外一种是可以在头文件最前面加上这个。

#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif   //__TEST_H__

高质量c/c++编程这本书出过这么两道题。

举报

相关推荐

0 条评论