Debugging C like it’s Python

I use the Python interpreter interactively and pdb
(as well as ipdb
) a lot and they let me understand my programs’ state and test new things out quickly.

When writing Flpc
in C, I found it a difficult to transition. In this post, I describe how to use gdb
to get a similar workflow.

In the course of that project, I also gained a much greater appreciation for C (compared to writing everything in assembly
). It is really convenient and macros when used in moderation lets me customize the language a bit to get around some quirks.

What I use in Python

pdb.stack_trace()sets breakpoints in code. I know its possible to set breakpoint from
the debugger but I find the uniform syntax (for my code and the debugging commands) is easier to remember and use. [1]

from pdb import set_trace as bp

def some_problematic_function():
    if some_condition:

Once bp()
is called, I get a REPL in which I can examine values

(pdb) p some_var
(pdb) p f(some_var) + 4

I can move forward by single steps (examining values in between) and eventually continue if all is well.

(pdb) s
(pdb) s
(pdb) n
(pdb) c

If bp
is called rarely enough, this lets me get to the crux of the problem quickly without setting up explicit conditionals.

I also tend to throw bp
around when I add new functions (by breaking at the beginning of the function) or new functionality to an already defined one. This lets me test with real data instead of artificial data.

Using the !
prefix, I can run commands with the function’s input values and then paste commands that worked back into my text editor. I’ve even started adding blank functions with just bp()
in the body! Again, this lets me write the function with a sample input in hand. pdb.post_mortem
) starts post-mortem debugging. I tend to run Python with -i
for interactive mode. And when the program crashes, I’ll start the debugger.

>>> import pdb;

I’ll move around the stack and examine values. This removed almost all the print statement (and logging
) debugging I used to do. It lets me examine value I wouldn’t have thought of printing beforehand when I started the program.

Its unfortunately not possible to continue (with c
) in this case.

Using gdb

Compile the binary to include more debugging information.

$ gcc -gdwarf-2 -g3 flpc_all.c -o flpc
$ gdb ./flpc
(gdb) r 

With that, gdb
can expand macros

(gdb) p some_var
(gdb) p some_macro(some_var) + 4

and make calls

(gdb) call ps()

To get the same effect as pdb.set_trace
, I create an empty function bp

void bp() {}

and set a breakpoint there before running the program.

(gdb) b bp

Similarly, when an error occurs, I route all of them to a function _error
defined as

void _error(char *s){
  printf("%sn", s);

and use it like so.

if (pop(local_stack) == Sep){
  _error("Popping empty data stack!n");}

Like bp
, I set a breakpoint on _error
before running the program.

(gdb) b _error

If only the input to my program changes but the source doesn’t, I don’t need to exit gdb and can just rerun

(gdb) r 

each time.


[1] Version control help me find and remove these before commiting.

Posted on Feb 17, 2017

Blog index

Lobsters稿源:Lobsters (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合编程 » Debugging C like it’s Python

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录