调试指南
由于图床一些问题,本篇博客暂时不添加图片,可以自行运行代码片段查看运行结果。
一、预处理指令的妙用
参考文献:爽文219
1、使用ifdef注释
只有在宏定义了ifdef后判断的内容时,使用ifdef和endif括住的内容才会被编译运行。
样例:
int main() { #define lky233 #ifdef lky233 freopen("testdata.in", "r", stdin); freopen("testdata.out", "w", stdout); #endif int a, b; cin >> a >> b; cout << a + b << endl; }
除了使用define进行宏定义,还可以在编译命令中添加 -D *** 实现。
例如:-D lky233
另外,ifndef表示若没有定义。
样例:
int main() { #define lky233 #ifndef lky233 freopen("testdata.in", "r", stdin); freopen("testdata.out", "w", stdout); #endif int a, b; cin >> a >> b; cout << a + b << endl; }
还有就是,一般常用的OJ都有宏定义ONLINE_JUDGE。
(HOJ也有的)
2、define
define在调试中用来进行宏定义,并用来一句话注释所有调试代码
#define debug #ifdef debug printf("debug"); #endif
3、warning/pragma message()
使用warning/pragma message()在一些修改处进行警告,防止自己失智。
int main() { #warning int a,b; #pragma message("debug") cout << a << b << endl; }
二、cerr的使用
输出一些调试信息,但没有注释导致$\color{red} \mathrm {WA} \(?。 为了查看调试信息注释了freopen? 不要慌,快用\)cerr$。
cerr 一个ostream对象,关联到标准错误,通常写入到与标准输出相同的设备。默认情况下,写到cerr的数据是不缓冲的。Cerr通常用于输出错误信息与其他不属于正常逻辑的输出内容。 ——百度百科
简单来说,cerr可以在你已打开文件输入输出的时候,依旧在屏幕上输出信息, 而非在文件中输入输出。
使用和cout是一样的。
int main() { freopen("testdata.in", "r", stdin); freopen("testdata.out", "w", stdout); cerr << 1 << endl; cout << 2 << endl; }
另外一提,syzoj可以输出你的标准错误流。在OJ上debug
关于标准错误流, 还有一个clog,没用过,感兴趣的自己康康。
三、assert
用于判断一些错误。
assert(),传入一个bool表达式,如果信息为假,程序会停止并抛出错误信息。
int main() { assert(0); }
四、使用dev进行debug
这个是dev的debug,要想学习gdb调试:请点我(虽然本质区别不大)由于个人感觉dev的debug太难用了,大多数情况我个人还是喜欢手动调试。
使用时编译器先选择debug,之后进行编译。
由于一些缓冲区的问题,建议使用文件输入输出。否则可能不可预测的翻车。
编译完成后摁下\(F5\)进行调试。
1、设置断点
调试情况下若没有断点程序将会直接正常运行,并且不会在控制台暂停。
单击行号以在该行设置断点。
程序会在这一行暂停运行。
2、添加查看
单击添加查看,输入变量名称,在左侧项目管理栏便可以看到所要查看的变量。
运行过程中,右键可以修改变量值。
3、下一步/单步进入
单击[下一步]或使用\(F7\)进入下一步。将会执行下一个函数。
单击[单步进入]或使用\(F8\)进入该函数进行调试。
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 10; int n; int a[MAXN]; inline void out() { for(register int i = 1; i <= n; ++i) { cout << a[i] << '\n'; } } int main() { #ifdef lky233 freopen("testdata.in", "r", stdin); freopen("testdata.out", "w", stdout); #endif scanf("%d", &n); for(register int i = 1; i <= n; ++i) { scanf("%d", &a[i]); } out(); return 0; }
4、RE报错
当调试一个RE的程序时,dev会暂停在RE的那行。如果是在函数中RE,会跳转到函数中。包括库函数,比如STL。折腾半天想找一个RE的程序
我也不知道为什么负下标没有RE。
但是,scanf不传地址就会RE啊。(初学C++常犯错误)
#include<bits/stdc++.h> using namespace std; const int MAXN = 100; int a[MAXN]; int n; int main() { #ifdef lky233 freopen("testdata.in", "r", stdin); freopen("testdata.out", "w", stdout); #endif scanf("%d",n); }
五、对拍
对拍是考场debug、证明正确性以及平时调试的利器。贪心只能过样例
1、一个重要的maker
#include<bits/stdc++.h> using namespace std; int main() { freopen("testdata.in", "w", stdout); srand(time(0)/* *new int */) int a = rand() % 10 + 1; int b = rand() % 10 + 1; cout << a << b << endl; }
2、对拍程序
#include<bits/stdc++.h> using namespace std; int main() { for(register int i = 1; i <= 10000; ++i) { system("maker.exe"); system("force.exe"); system("right.exe"); //system("force.exe<testdata.in>force.out"); //system("force.exe<testdata.in>right.out"); if(system("fc force.out right.out")) { puts("wrong"); exit(0); } } }