一篇思维导图送给大家(总结思维导图真的提升非常大);
目录
预处理
一些预定义符号
__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++编程这本书出过这么两道题。