【技巧】Debug

OI中,很少人能写题一遍过。大部分人在过完编译后,会因为种种原因RE/WA/TLE,这时就需要Debug,这里分享一些Debug的技巧。

干瞪眼

这个没啥说的,看代码就行,有时候犯一些低级错误很容易看出来

编译命令

  • -Wall,也就是$Warning All$的缩写
  • -Wextra,也就是$Warning Extra$的缩写

-Wall

在编译时加上-Wall命令,比如这样

g++ a.cpp -o a -Wall

这会让你看到一部分粗心犯的错误,比如表达式忘加括号等

-Wextra

g++ a.cpp -o a -Wextra

这会显示一些奇怪的东西,比如类型为int的函数没有用到返回值,会蹦出警告

C/C++语法

错误流

C

fprintf(stderr, "a : %d ", a);

printf一样,只不过是输出到错误流。也就是说,如果对标准流stdout进行freopen写文件后,向stderr输出的东西还会进入终端而不是文件。所以,向Online_Judge上交代码时,错误流并不需要注释掉。

C++

cerr << "a : " << a << ' ';

使用方法类似cout,区别是向错误流输出,交题时也不需要注释掉。

assert.h/cassert

这里提供了一个函数assert(bool),在这个函数里传一个表达式,如果不满足条件,它会直接退出程序,并在终端显示错误信息。比如,我为了防止写的SegmentTree出现问题,就加了这么一句

void Modify(int now, int l, int r, int nl, int nr, int k) {
    assert(r >= l);
    if (l == nl && r == nr) {
        tag[now] = (tag[now] + k) % mod;
        return;
    }
    int mid = nl + nr >> 1;
    tree[now] = (tree[now] + k * (r - l + 1) % mod) % mod;
    if (r <= mid) {
        Modify(now << 1, l, r, nl, mid, k);
    } else if (l >= mid + 1) {
        Modify(now << 1 | 1, l, r, mid + 1, nr, k);
    } else {
        Modify(now << 1, l, mid, nl, mid, k);
        Modify(now << 1 | 1, mid + 1, r, mid + 1, nr, k);
    }
}

这样,它会在$l$>$r$的时候退出程序,并显示错误信息,我就能知道是否是这个函数出现了问题。

gdb

这个东西就很好用了,刚学会使用dev-cpp时就会用图形化的gdb了,后来因为OI考场上没有dev-cpp,所以学了命令行的gdb。并且使用Emacs自带的gdb-many-windows插件特别方便,比图形化还丝滑。

编译命令

g++ a.cpp -o a -g3

然后使用gdb打开,就可以debug了,常用的操作有这么几个:

  • 设置断点:b 然后一个数字,为断点行数
  • 查看变量: display 然后加表达式,注意在namespace中的需要加 namespace名 ::
  • 跑代码: n,疯狂按就好了

重构

要没啥办法就重构吧。