Calculation

Now it’s time to make a program that does do something. Perhaps it should calculate the answer to the age-old question, ‘What is \(2 + 2\)?’. Put the following code in twoplustwo.c.

int main()
{
    int x = 2 + 2;
}

If you compile and run this program, you will find that it still apparently does nothing. In fact, it does calculate \(2+2\), it just doesn’t say anything about it. C is a very minimalist language, and as we’ve seen, even something like printing answers where a human can see them is left off for a library. For now, let’s use another way of seeing what’s going on inside this program: an interactive debugger.

As we will see in this course, you can do a lot using a debugger without the program’s cooperation; however, it is more convenient to debug a program when the compiler cooperates by including some additional information. The default rules for make are adequate for you to run make twoplustwo and rely on it to figure out to use twoplustwo.c and the C compiler, but we’re going to need a Makefile anyway in order to tell it to pass some additional options when it runs the compiler. This Makefile can be a one-liner.

CFLAGS=-g -Wall

You can also set up phony all and clean targets if you wish, but the options specified in the CFLAGS variable will be sufficient. The -g option is the crucial piece, which instructs the compiler to include debugging symbols. The -Wall option is something I always prefer to use; it stands for ‘Warnings, all’ and makes the compiler a little more verbose about things it thinks might be wrong with your code.

If you have already built the program, running make twoplustwo will just tell you that everything is up-to-date. You can delete the program with rm, or you can make it seem like there are changes to the source file. Running touch twoplustwo.c will update its timestamp as though you had just edited it.

Now that we have configured the compiler correctly and rebuilt the program, open it in the debugger by running gdb twoplustwo. The debugger is a command-prompt environment like the shell; to prompt you for a command, gdb will print (gdb). You type a command and press enter, and when gdb is ready for your next command it will print the prompt again.

Start the program running with start. It will pause at the beginning of main, and you can step through line by line with next. After x has been calculated, when the program is paused on the closing curly bracket, you can print out the value of x.

(gdb) start
Starting program: ...

Temporary breakpoint 1, main () at twoplustwo.c:2
2               {
(gdb) next
3                       int x = 2 + 2;
(gdb) next
4               }
(gdb) print x
$1 = 4

The output $1 = 4 is telling us that if we want to use this result again, we can call it $1, but more importantly, that the value is 4.

To continue experimenting with calculations and the debugger, put the following in factorial.c and build it. (The Makefile we already made will apply to anything you build in that directory, so there is no need to duplicate that step to get the compiler options we want.)

int main()
{
    int n = 1;
    n = n * 2;
    n = n * 3;
    n = n * 4;
    n = n * 5;
}

Step through the code in gdb with start, next, and print n to watch the program calculate the factorial.

One more example will show us another of C’s datatypes, double, which can handle fractions, and let us use the debugger to manipulate a running program. Put this one in temperature.c and step through it in the debugger as we have been doing, printing celsius and fahrenheit to follow the calculation.

int main()
{
    double celsius = 20.0;
    double fahrenheit = celsius * 9.0 / 5.0 + 32.0;
}

Now, step through temperature in the debugger again, but as soon as celsius has been initialized to 20.0, change it! What temperature would you like to convert? To convert, say, 100°, tell gdb print celsius = 100.0, then continue stepping through and you will see the calculation proceed using your changed value.

You have attempted of activities on this page