调试输出工具
调试输出工具
一句话工具
debug(a, b, c) 把变量名和值一起输出,让你在本地调试时少写重复的 cerr << ...。
适用场景
调试输出工具解决的是一个很小但很高频的问题:程序跑错时,我们通常需要知道某几个变量在某一行的真实值。
普通写法会变成:
cpp
1
cerr << "i = " << i << " j = " << j << " ans = " << ans << "\n";
变量一多,代码就又长又容易写错。这个模板把“变量名”和“变量值”绑定在一起输出:
cpp
1
debug(i, j, ans);
输出中会带上当前行号,适合快速定位是哪一次调试输出。
核心接口
debug(x):输出一个变量。debug(a, b, c):按顺序输出多个变量。debug_line:输出一条分隔线,适合把多轮调试信息隔开。
模板默认输出到 cerr,不会和正常答案的 cout 混在同一个缓冲逻辑里;但在线评测只看标准输出时,仍然建议提交前关闭调试输出。
使用步骤
- 把模板放在
main前面。 - 在怀疑出错的位置写
debug(...)。 - 本地样例调试完成后,删除调试语句,或者用宏开关统一屏蔽。
例如排查双指针时,可以在每次移动指针后输出状态:
cpp
1
debug(l, r, sum);
排查图论搜索时,可以在进入节点时输出:
cpp
1
debug(u, parent, depth[u]);
代码实现
模板文件位置:/code/utils/log.cpp。
cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <bits/stdc++.h>
using namespace std;
#define debug_line cerr << "\n=================\n"
#define debug(...) \
do { \
cerr << "LINE:" << __LINE__ << " "; \
string names = #__VA_ARGS__; \
replace(names.begin(), names.end(), ',', ' '); \
stringstream ss(names); \
istream_iterator<string> it(ss); \
debug_print(it, __VA_ARGS__); \
} while (false)
void debug_print(istream_iterator<string>) {}
template <typename T, typename... Args>
void debug_print(istream_iterator<string> it, const T& value,
const Args&... args) {
cerr << *it << " = " << value << "\n";
debug_print(++it, args...);
}
常见改法
提交前关闭调试
如果不想手动删除所有 debug(...),可以给模板加一个编译开关:
cpp
1
2
3
#ifdef ONLINE_JUDGE
#define debug(...)
#endif
本项目的通用竞赛模板里也提供了类似的 NO_DEBUG 开关。
输出容器
当前模板依赖 operator<<。int、long long、string 这类类型可以直接输出;vector<int>、pair<int,int> 默认不能直接输出。
如果你经常调试容器,可以额外给容器补输出重载:
cpp
1
2
3
4
5
6
7
8
9
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& a) {
os << "[";
for (int i = 0; i < (int)a.size(); ++i) {
if (i) os << ", ";
os << a[i];
}
return os << "]";
}
控制输出位置
模板默认用 cerr。如果你的运行环境只方便看标准输出,也可以把 cerr 改成 cout;但这样更容易污染答案输出,提交前必须确认调试已经关闭。
注意事项
debug(a, b + c)可以用;但包含逗号的复杂表达式不适合直接放进去,例如debug(make_pair(x, y))的变量名解析会不准确。- 调试输出会影响运行速度,尤其是在循环内部大量输出时。
- 调试宏只适合本地排错,不应该依赖它产生正式答案。
- 如果题目要求输出格式严格,提交前要保证没有任何调试信息进入标准输出。
推荐用法
这类工具最好固定放进自己的个人模板。平时保留 debug(...) 接口,比赛时用开关控制是否启用,这样不用在不同题目之间反复复制粘贴调试写法。