引言
信息学竞赛的初学者总是容易犯一些低级错误------忘记文件 IO,忘记删调试信息,变量名、函数名冲突等。同时,当竞赛选手需要写部分分或遇到一些特殊情况(比如程序需要根据不同的数据范围选择不同的计算方案)时,也需要一些工具优化代码的组织结构。这时,宏定义便成为了有效的工具。
正文
使用
宏定义是 C 语言和 C++ 中的一种预处理指令,允许程序员在源代码中定义一个标识符,以便在后续的代码中用该标识符代替特定的值或代码块。宏定义在代码编译之前会被预处理器进行处理,其作用类似于进行代码替换,有助于提高代码的可读性和可维护性。它的用法时这样的:
cpp
#define <宏名>(参数) <字符串>
例如,#define int long long
能够在编译时将 int
字符串替换为 long long
。
常见与其配合使用的还有这些语句:
语句 | 含义 |
---|---|
#ifdef <宏名> |
检查宏是否被定义 |
#ifndef <宏名> |
检查宏是否没有被定义 |
#endif |
作为ifdef 和ifndef 的结束标志 |
#else |
作为ifdef 和ifndef 的否定 |
#undef <宏名> |
取消宏定义 |
也就是说,宏定义会对代码中的表示符进行"替换"。下面是一个使用宏定义编写 A+B 问题代码的例子:
cpp
#include <iostream>
#define int long long // 宏定义 int
int a, b, c; // 此处将按照 long long 编译
#ifdef int
#undef int // 宏定义 int 结束
#endif
#define ADD(x,y) x+y // 宏定义 ADD
int main() { // 此处将按照 int 编译
#ifndef ONLINE_JUDGE
// 如果编译时使用了 -DONLINE_JUDGE 则不会使用文件读写
freopen("aplusb.in", "r", stdin);
freopen("aplusb.out", "w", stdout);
#endif
std::cin >> a >> b;
c = ADD(a,b); // 此处将按照 a+b 编译
std::cout << c << std::endl;
return 0;
}
由此可见,宏定义能够辅助编写代码,并降低因忘记文件读写等问题导致丢分的概率。善用宏定义能够在大型考试中快速调试代码,并解决一些常规方法不易解决的问题。
注意事项
- 运算优先级。例如,如果定义
pf(x)
为x*x
,则pf(a+b)
将被替换为a+b*a+b
,可能不符合预期,因此可能需要适当加入括号调整运算优先级。例如,如果想让替换结果变为(a+b)*(a+b)
,定义可能需要写成#define pf(x) (x)*(x)
。 - 传参的计算次数。例如,如果定义
#define ABS(x) (x>0)?x:-x
,则ABS((pd()))
将会被替换为((pd())>0) ? (pd()) : -(pd())
,导致pd
被执行 \(2\) 次。如果pd
的运算结果变化则会出错,而且程序运行时间也会大大加长。
致谢
感谢 tristiano 对文章编写的帮助。