2009-09-09

Post date: Sep 10, 2009 1:02:59 AM

    • Compile hello.c (attached) with this command: gcc -save-temps hello.c
      • hello.i is the C code after preprocessing the #include <stdio.h> directive. Our code for main() is located far down in the bottom. This code is largely untouched. The stdio.h header contains the prototype declaration for printf() so the compiler knows how to generate code for calling the function. It does not contain the source code for the implementation of printf().
      • Incidentally, it is possible to compile hello.c without the #include line. The compiler infers the number of arguments from the call site (1 argument in this case) and assumes it to be an int. This causes gcc to issue a warning "incompatible implicit declaration ..." because we're passing a string "hello world\n" (which is a const char *, pointer to an array of constant characters) to an argument which accepts int. But omitting the prototype is unsafe. It is highly recommended to pass -Wall (causes gcc to give more warnings) and -Werror (turn all warnings into errors) flags if you want the gcc compiler to do its best informing you of unsafe practices.
      • hello.s is the assembly code after compiling hello.i. Note that your output would be slightly different if you're on Windows (using gcc under Cygwin) or Mac OS X. Notice that the assembly code does not actually call printf(); it calls puts() instead. That's because the compiler sees that you don't actually have any format specification (e.g. "%d" or "%s"), and the string ends in a new line. The compiler chops off the new line and changes the call to puts(), which adds a newline character to the string.
      • Removing the newline "\n" from "hello world.\n" forces the compiler to use printf() again; this can be verified.
    • Show how to retrieve command line arguments (see args.c attached).
      • Memory is a big flat array of bytes, and a pointer is the memory location that contains the byte we want. In C, pointers and arrays are indistinguishable, since array elements occupy continuous memory locations. The pointer always points to the first element and can be advanced like array reference.
      • In the argument type int main(int argc, char **argv) { ... }, we can also write char *argv[], so argv is an array of character pointers. Each pointer refers to a character array. A C string is an array of characters (of unknown length) followed by a NUL character.
      • for (int i = 0; i < argc, i++) { ... } only works in C99 mode (pass -std=c99 to gcc). Otherwise split it into two lines: int i; for (i = 0; i < argc; i++) { ... }
    • Use C preprocessor directive to put together a simple debugging package (see preproc.c)
      • #define can be used to define macros that take arguments.
      • Macros can be defined based on the presence of other macros.
      • Define a macro for debug output. It is defined to call printf() if the DEBUGGING flag is set, or the empty string (which means no printf() is called) if DEBUGGING is undefined.