目录
已经设置的预定义符号,可以直接使用,预定义符号在预处理期间处理.
#include <iostream>
int main()
{
using namespace std;
cout << __FILE__ << endl;//编译的源文件
cout << __LINE__ << endl;//当前文件的行号
cout << __DATE__ << endl;//编译的日期
cout << __TIME__ << endl;//编译的时间
//cout << __STDC__ << endl;//如果编译器支持ANSI C,其值为1,否则未定义
return 0;
}
?
?
基本形式:
#define name stuff
?
#include <iostream>
#define MAXX 100//定义标识符常量
#define ll long long//为关键字创建更短的名字
#define p a
#define do_10 for(int i = 0; i < 10; i++)//用符号来表示这个实现过程
#define CASE break; case//定义CASE,使其不用多次写break;
#define DEBUG_PRINT cout << __FILE__ << endl\
<< __LINE__ << endl\
<< __DATE__ << endl\
<< __TIME__ << endl;// \是续行符
int main()
{
using namespace std;
ll a = 100;
cout << p << endl << endl;;
do_10
{
cout << i << endl;
}
cout << endl;
switch (5)
{
case 1:cout << 1 << endl;
CASE 2:cout << 2 << endl;
CASE 3:cout << 3 << endl;
CASE 4:cout << 4 << endl;
CASE 5:cout << 5 << endl;
CASE 6:cout << 6 << endl;
}
cout << endl;
DEBUG_PRINT;
return 0;
}
?
?注意!#define在预编译阶段直接把定义展开,所以一般#define定义后面不加;
?
#define 定义宏允许把参数代替到文本中
基本形式:
#define name(parament-list) stuff//name后面的括号必须紧邻
#include <iostream>
#define Add(x, y) x + y
int main()
{
using namespace std;
int ret = Add(42, -13);
cout << ret << endl;
return 0;
}
?
?再来看看这个代码:
#include <iostream>
#define Mul(x,y) x * y
int main()
{
using namespace std;
int ret = Mul(3 + 3, 4 + 2);
cout << ret << endl;
return 0;
}
?
?
?为什么不是36而是17呢,前面说过了,预处理是直接将#define替换,上面替换后:
3 * 4
3 + 3 * 4 + 2
?由优先级和结合律易得17,所以定义宏时要将参数括上括号,再将总体加上括号:
#include <iostream>
#define Mul(x,y) ((x) * (y))
int main()
{
using namespace std;
int ret = Mul(3 + 3, 4 + 2);
cout << ret << endl;
return 0;
}
?
副作用就是表达式求值时出现的永久性效果,当宏参数在宏定义中出现超过一次的时候,参数带有副作用,使用宏可能会有危险。
#include <iostream>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main()
{
using namespace std;
int a = 10;
int b = 6;
int ret = MAX(a++, b++);
cout << ret << endl;
cout << a << endl << b << endl;
return 0;
}
?
?a++与b++首先在比大小时各自加1,此时a == 11 ;b == 7; 判断为真,执行(x),此时返回 a == 11的值,返回后a自增1 ,此时a == 12。
1.调用宏时,首先对参数进行检查,看看是否包含任何#define定义的符号,有则首先被替换。
#include <iostream>
#define A 100
#define B 200
#define MAX ((A) > (B) ? (A) : (B))
int main()
{
using namespace std;
int ret = MAX;
cout << ret << endl;
return 0;
}
?2.替换文本随后被插入到程序中原来文本的位置,宏,参数命被它们的值替换
3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号,如果是,就重复上述处理过程。?
4.不能递归#define定义,即不能在#define里面再#define,但可以出现其他#define 的符号。
?
5.当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。比如“A”就是“A”,并不会被替换成“100”.?
宏函数常被应用于执行简单的运算,因为:
1.调用常规函数并返回可能比宏函数执行时间要长,因为常规函数要由开辟函数栈帧等一系列操作,宏函数对比常规函数执行小型运算规模和速度会更胜一筹。
2.我们已经注意到了,上面定义宏函数我们并没有给出返回值和参数的类型,而常规函数需要指出类型。
但宏函数也有其缺点:
1.使用宏定义时,预编译时属于文本替换,除非宏函数比较短,否则可能大幅度增加程序的长度。
2.宏函数没办法调试,常规函数可以进入函数内部逐句调试。
3.宏函数没指出类型,可能不够严谨;
4.宏可能出现运算优先级问题(记得加括号)
宏也可以做到常规函数做不到的事情,宏的参数可以出现类型,常规函数做不到这一点:
#include <iostream>
#define MALLOC(num,type) (type*)malloc(num * sizeof(type))
int main()
{
using namespace std;
int* ptr = MALLOC(10, int);//替换后(int*)malloc(10 * sizeof(int))
for (int i = 0; i < 10; i++)
{
*(ptr + i) = i + 10000;
}
for (int i = 0; i < 10; i++)
{
cout << *(ptr + i) << endl;
}
return 0;
}
?
#运算符将宏的一个参数转换为字符串字面量,它仅允许出现在带参数的宏的替换列表中。
#include <iostream>
#include <cstdio>
#define Print(a) printf("The value of " #a " is %d",a)
int main()
{
using namespace std;
int b = 10;
Print(b);
return 0;
}
?
## 可以把位于两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符,##被称为记号粘合,这样连接必须产生一个合法的标识符,否则其结果未定义。
应用于宏定义常规函数:
#include <iostream>
#define MAX(type)\
type type##_Max(type x,type y)\
{ \
return ((x) > (y) ? (x) : (y));\
}
MAX(int);
MAX(double);
int main()
{
using namespace std;
int ret = int_Max(2, 3);
cout << ret << endl;
double ret2 = double_Max(1.3, 4.5);
cout << ret2 << endl;
return 0;
}
这样就避免了类型不同但结构相似的函数的重复编写。?如果没有##,上面就只有type_Max()一个函数。
移除一个宏定义
常见的条件编译指令:
#if 常量表达式
//...
#endif
#if 常量表达式
//...
#elif 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
//判断是否被定义
#if defined(symbol)
//...
#endif
#ifdef symbol
//...
#endif
#if !defined(symbol)
//...
#endif
#ifndef symbol
//...
#endif
#include <iostream>
int main()
{
using namespace std;
int arr[10];
int j = 0;
for (int &i : arr)
{
i = j + 1;
j++;
}
#if 1
for (int i : arr)
{
cout << i << endl;
}
#endif
return 0;
}
?
?
#include <iostream>
#define MAXX 100
int main()
{
using namespace std;
#if MAXX == 1
cout << 1 << endl;
#elif MAXX == 90
cout << 2 << endl;
#elif MAXX == 100
cout << 3 << endl;
#else
cout << 4 << endl;
#endif
return 0;
}
?
?
#include <iostream>
#define MAXX 100
int main()
{
using namespace std;
#if defined(MAXX)
cout << 1 << endl;
#endif
#ifdef LIN
cout << 2 << endl;
#endif
#if !defined(LIN)
cout << 3 << endl;
#endif
#ifndef MAXX
cout << 4 << endl;
#endif
return 0;
?
?条件编译可以嵌套:
#include <iostream>
#define MAXX 100
int main()
{
using namespace std;
#if MAXX == 100
#ifdef MAXX
cout << 1 << endl;
#endif
#ifndef LIN
cout << 2 << endl;
#endif
#if MAXX == 99
cout << 3 << endl;
#else
cout << 4 << endl;
#endif
#endif
return 0;
}
?
头文件包含形式有:
#include <>//本地文件包含
#include ""//库文件包含
?两种的区别在于查找顺序不同:
#incldue "":先在源文件所在目录下查找,如果该文件未找到,编辑器就像查找库函数头文件一样在标准位置查找头文件。
#include <>:直接去标准位置查找,找不到就报错。
对于本地文件和库文件,都可以用#include “”,但对于库文件来说,最好用#include<> ,因为#include ""多了一步查找,对于库文件是没必要的,会导致查找效率变低。
?这样预编译时会进行5次文本替换,如果工程量大,预处理后代码量剧增,应该避免重复引用。
可以使用条件编译来解决头文件重复引用:
?也可以用#pragma once
?这样头文件就只引入一次。