All programmers know that it takes a lot of work to write good code. Even very good experienced programmers only manage to write an average of a few lines of (efficient, debugged) code a day. Most programmers rely on some kind of debugging tools to help find bugs in their code. And there are many different debugging tools around. On this page I present an include file for C programming that will help debug programs, by writing selective information to a log file. Some of the ideas behind this tool were learned when I worked for a computer graphics firm in Rio de Janeiro, way back in 1986 and 1987. Even being so old, the concepts still apply. The main idea is to define some DEBUG statements that can be included (or not) in your final code. All that is needed to include the code is to define a compile variable. If the variable is not defined, the program will be compiled without any of my debug tools. If the variable is defined, then the program will be compiled with the code, and a selective log file will be generated. The code bits I supply here are free of charge, and can be used in just about any C program. It can also be modified slightly and be used in other languages (such as PHP). The main difference in other languages is that most don't have the preprocessor, and therefore the commands cannot be included and excluded as in C. But, they can be substituted for IF statements, and this way only the IF statement will be executed, and not the debug code if the IF statement comes up false. Of course, just because the code can be used free of charge, doesn't mean that if you find the code useful, you can't thank the author. If you use the code, and find it helpful, please thank the author. If you want, you can even send him a pizza (or the cash to buy one). That is just a suggestion, of course. Now, on with the tips: Here I will explain the concepts, and you can take your pick:
The file starts with the preprocessor directive #ifdef DEBUG #ifdef DEBUG The first things we define are:
Just like the first section, the second section starts with the preprocessor directive: #ifdef DEBUG #ifdef DEBUG The DEBUG_OPEN code is basic code to open a file in write-only mode, truncate it, and create it if it doesn't already exist.
If there is an error in creating/truncating the file, this will be reported, and your program execution terminated. The next two sections deal with entering and exiting functions or subroutines. /* The idea of the indentation is that for each function you enter, you offset the text 2 spaces. Then for each function you exit, you subtract 2 spaces from the indentation. This make it easy on the eye to spot where you entered and exited functions or subroutines, in the generated log file. The next 3 sections deal with the debug level. Here we can equate, or bitwise set or reset each of the bits (int) of the level. /* Each bit can be assigned to a certain type of action in our main program. Since we are dealing with each bit, our int is formed by several bits (at least 16) and each one represents a power of 2 (in decimal notation). As an example, lets say we code all the input parts of our program as 1, all our output parts as 2, our loops as 4, and our calculated values as 8. In this way we can add what parts we want to log data for, like this:
With our predefined routines we can set or reset each bit individualy, or we can just plain assign a complete new value to our debug level. The next 4 sections deal with writing the data to the log file. Each one will only write the data to the log file, if the level requested in the command has been previously set in the master debug level. Just like our example above, with input, output, loops, and calculations. /* The difference in the 4 routines is in the formatting of the string to print. The first routine (DEBUG_WRITE(level, string)) takes 2 parameters: the debug
level at which to print the string, and the preformated string to print.
As long as the level is satisfied, the string will be added directly to the log file, just as it is. The second routine (DEBUG_WRITE2(level, string1, string2)) takes 3 parameters: the debug level at which to print the string, the string to print (using sprintf) and one variable. As long as the level is satisfied, the string will be printed to the log file, following the rules for sprintf(logfile, "formatted string %d\n", string2) The formatted string can include ONE variable parameter to be printed, usually a %d, %f or %s. The third routine (DEBUG_WRITE3(level, string1, string2, string3)) takes 4 parameters: the debug
level at which to print the string, the string to print (using sprintf) and two variables. The fourth routine (DEBUG_WRITE4(level, string1, string2, string3, string4)) takes 5 parameters: the debug
level at which to print the string, the string to print (using sprintf) and three variables. The next section was written specifically for my PhD work, because I use frames and vectors. This macro writes a vector (or frame) to the debug.log file. For this macro we pass the level, the vector, the length of the vector (or frame), and the string of the type data to print (typically "%d" or "%f"). /* ** Write a vector ** EX: DEBUG_WRITE_VECTOR(1, vector, length, "%f"); */ #ifdef DEBUG #define DEBUG_WRITE_VECTOR(level,vector,size,string) if(level & debug_level) { \ for(debug_loop_count = 0; debug_loop_count < debug_indent; debug_loop_count++) write(debug_log_fp, " ", strlen(" ")); \ for(debug_loop_count2 = 0; debug_loop_count2 < size; debug_loop_count2++) { \ sprintf(debug_txt_tmp, string, vector[debug_loop_count2]); \ write(debug_log_fp, debug_txt_tmp, strlen(debug_txt_tmp)); \ } \ sprintf(debug_txt_tmp, "\n"); \ write(debug_log_fp, debug_txt_tmp, strlen(debug_txt_tmp)); \ } #else #define DEBUG_WRITE_VECTOR(level,vector,size,string) #endif Then, our last section just closes the log file that we opened at the beginning. Just plain good programming practice. /* As in most C programs that do anything useful, to be able to compile a program using our debug.h macro definitions, several system include files need to be used: #include <stdio.h> Just to help you a little more, I have a sample program in C and a Makefile you can use to try out my debug.h macros. |
English Version > Documents and tutorials >