Thursday, November 21, 2013

K&R C SE Lesson 2: Introducing printf, the 'for loop', and gdb

(Post Under Construction)
This post uses an example from the first chapter of  K&R C Programming Second Edition. After discussing the use of the printf function, K&R C SE demonstrates alternate code for printing a Fahrenheit-Celsius conversion table. The specific and compact use of printf arguments allows for the appropriate formatting of the results returned by a compact conversion routine inside of a for loop. This code is more compact and more accurate than the first example in Lesson 1 using the while loop:

#include <stdio.h>
/* print Fahrenheit-Celsius table */
main()
{
int fahr;
for (fahr = 0; fahr <= 300; fahr = fahr + 20)
        printf("%3d %6.1f\n", fahr, (5.0/9.0) * (fahr-32));
}

You can compile the code above (after creating the text file "FAHRfor.c") with gcc as below on Cygwin X11 terminal.On a MAC you will not need to append '.exe' to your compiled executable file name. The option '-o' specifies the output binary or compiled file name. 

 gcc FAHRfor.c -o FAHRfor.exe

Running the binary on Cygwin produces the conversion table:

 ./FAHRfor.exe
  0  -17.8
 20   -6.7
 40    4.4
 60   15.6
 80   26.7
100   37.8
120   48.9
140   60.0
160   71.1
180   82.2
200   93.3
220  104.4
240  115.6
260  126.7
280  137.8
300  148.9

gcc has many options. Use 'man gcc' or 'info gcc' for more information. The option '-g' creates code with symbols useful for debugging.

 gcc  -g FAHRfor.c -o FAHRfor.exe

gdb or gnudbg allows the user to 'step' through code compiled with '-g' option. You start it by suffixing the binary or compiled file name to gdb. At the gdb prompt we will set a 'breakpoint' for each line in the source code. Next we will 'run' the code (inside of gdb) and then 'step' through the execution of each conversion in the for loop. I have marked in bold the debug output results of the first two lines of conversion.

 gdb FAHRfor.exe
...
Reading symbols from /home/rferrisx/FAHRfor.exe...done.
(gdb) break 1
Breakpoint 1 at 0x40117e: file FAHRfor.c, line 1.
(gdb) break 2
Note: breakpoint 1 also set at pc 0x40117e.
Breakpoint 2 at 0x40117e: file FAHRfor.c, line 2.
(gdb) run
Starting program: /home/rferrisx/FAHRfor.exe 
[New Thread 10972.0x3618]
[New Thread 10972.0x14a4]

Breakpoint 1, main () at FAHRfor.c:6
6       for (fahr = 0; fahr <= 300; fahr = fahr + 20)
(gdb) s
7               printf("%3d %6.1f\n", fahr, (5.0/9.0) * (fahr-32));
(gdb) s
  0  -17.8
6       for (fahr = 0; fahr <= 300; fahr = fahr + 20)
(gdb) s
7               printf("%3d %6.1f\n", fahr, (5.0/9.0) * (fahr-32));
(gdb) s
 20   -6.7
....

Debugging is an essential skill for programming and debuggers have extensive functionality. Instrumented code can allow the programmer to output debug messages. However, most code can be debugged by producing a debug version of the source as we have demonstrated here.

No comments:

Post a Comment