Lab 12: The C Preprocessor and Debugging with Macros

Due: Wednesday, Nov. 19, 2014 @ 11:59 p.m.

Description:

In this lab, you will simulate working on a large project containing many different files. Many times with large projects, in order to keep things neat and orderly, source and include files are distributed across several directories. Generally (but not always), source (*.c) files are kept in a directory named src/, include (*.h) files are kept in a directory named inc/ or include/, and object files are kept in a directory named obj/. The executables for large projects are also generally kept in a directory named bin/.

You will create several source and include files, place them in the appropriate directories and create a Makefile that will compile and link an executable from these files.

You will also learn a technique that can be used to "conditionally compile" your code to either print out debug information or not, depending on the options found on the gcc command line.

Background Preparation:

  1. Read the following webpages:
    1. http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
    2. https://gcc.gnu.org/onlinedocs/cpp/Ifdef.html#Ifdef
    3. https://gcc.gnu.org/onlinedocs/cpp/Invocation.html#Invocation  (Concentrate on the -D and -I portions)
    4. https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html

Specifications:

Perform the following steps for this lab. It is strongly suggested that you perform all the steps on Zeus directly rather than on your own computer and then attempt copy them over to Zeus. Also, the instructors for the course are leaning towards performing all work on Zeus only, instead of Zeus and Mason. Although using Mason is still permitted, you are encouraged to begin using Zeus exclusively.

    int i = 0;
    int *p = (int *) malloc(sizeof(int) * ARRAY_SIZE);
    if (p == NULL)
    {
       fprintf(stderr, "function1(): Error allocating p\n");
       exit(1);
    }

    printf("In function1()...\n");

    for (i=0; i<ARRAY_SIZE; i++)
    {
        p[i]=i;
    }

#ifndef NDEBUG
    for (i=0; i<PARTIAL_SIZE; i++)
    {
        printf("function1(): %s = %d,%s = %d ", PR(i),i,PR(p[i]), p[i]);

        printf("\n");
    }
#endif
   
    free(p);
Submission:

After you have performed the steps given in the specifications, start a typescript session in the Lab12 directory which you created. Type "uname -a" to show that you are on mason or zeus. Use the ls and cat commands to list all your source and include files and the Makefile. (Hint: Use wildcards for cat'ing the files). Set the Debug compiler directive in the Makefile so that the code segments set off by the #ifndef NDEBUG directives are used (re-read the above Background Preparation links if you aren't sure what that statement means). Compile your program using the make command. Run your programs to show that it executes correctly.  You should notice a lot of output that is printed when the Debug directive is set.

Now, modify the Makefile so that pre-processing will remove the debugging print statements. Run your cleanall target for your Makefile. Then recompile your program with the make command. Run your program to show that it executes correctly. Notice that most of the output does not occur. Why? If you are not sure, experiment with the gcc pre-processor. The -E option on the gcc command line will run the gcc pre-processor only and show the resulting code. Compare the output files from the following commands:

gcc -E Function1.c  -I../include | tail -20

and

gcc -E Function1.c  -I../include -DNDEBUG | tail -20

(The tail command will print the last 10 lines (unless additional options such as -20 are used) of a file or stdout. More information can be found by using the man tail command.)

Also note the use of the #x pre-processor directive and what it does (re-read the stringification page of the Background Preparation).

Consider how you can use these new techniques in your debugging.

Run the clean target for your Makefile (not the cleanall target).

Exit the typescript session by typing crtl-d.

Verify that your script file was created correctly by using the more (or less) command (your choice) to see the contents of the file. As always, information on these commands can be obtained by using the manual pages ("man more" or "man less"). Once you are sure the file is correct, change back to the directory immediately above Lab12, and use the tar command to create an archive of all the files in the Lab12 directory. Name this archive Lab12.tar. Re-read the man page if necessary to discover the proper options to use.

Submit the Lab12.tar file to Blackboard as Lab 12.