Overview Read Appendix B. Structures Storage Allocation Use of extern/static/auto File/function scope malloc/free Separate Compilation Object files Symbol Tables Linking Other command line arguments review stdin/stdout + file IO/redirection Structures ============== The keyword 'struct' defines a group a type a single entity. Ex. I need to keep information on a word and how often it is used. Since this information is used together I could keep it together. struct word_count { char *wordp; int count; }; This defines a type and I can create variables/arrays of this type. main() { struct word_count w1; struct word_count words[100]; } You can also define pointers to this type. main(){ struct word_count w1; struct word_count words[100]; struct word_count *wp; wp = &w1; wp = words; } --> How would you malloc 1 struct word_count? 100 struct word_count? --> What is the type of *wp? --> Is wp + 1 a legal pointer? You refer to an element of the structure with '.' main(){ struct word_count w1; struct word_count words[100]; struct word_count *wp; wp = words; w1.wordp = "10th"; w1.count = 0; (*wp).wordp = "10th"; wp->count = 0; /*Short hand*/ } Storage Allocation =================== File Scope ----------- Symbols declared in the file scope are global. Global implies more than one function may use the definition of the variable. Ex int global_x = 0; int fun1() { global_x = 1; } int fun2() { printf ("%d\n", gobal_x) } The lifetime of the variable is the lifetime of the program. The variable maintains it's value until changed. Global variables may be shared between Object Files (.o)s Ex. extern int global_x; /* what happens if initialized */ int inc() { global_x ++; } You can make a variable local to the file scope (why would you?) -> variables with names like count (name clashing) -> modularity Ex. extern int global_x; /* what happens if initialized */ static int inc_count; /* visible only in funs2.c */ int fun3() { global_x ++; inc_count += 1; } Function Scope --------------- Variables declared inside a function are local to the function. The value of internally declared variable is visible only inside the function/ Ex. int fun1 () { [auto] int x = 0; if (x == 0) x = 1; } int fun2() { int y; printf ("%d", x); /* ERROR */ } The lifetime of an 'auto' is only during the invocation of the function. The auto variable loses it's value at the end of the function. A function 'sees' it's own scope and it's file scope. We can show the function other things. int fun2 () { int x; extern int global_x; printf ("%d\n", global_x); } We can also make a variable that looks like a global variable but is private to the function. int init () { static int done = 0; if (!done) { /* initialize */ done = 1; } } Both the static/extern storage declarators refer to storage in the data area. They also modify the visibility of the variable name. auto refers to variables that live on the stack and are temporary. --> Can a file variable ever be auto? --> What does the register storage class do (try it gcc -S)? malloc/free -------------- While 'lifetime' is defined in exact terms for extern/static/auto, variables allocated with malloc have inderminate lifetimes (left to the programmer). int *ip; int x; ip = &x; /* Ip points to some storage */ /* storage has lifetime of X == programs lifetime */ ip = malloc (sizeof (int)) /* Storage is alive until 'free' */ int *jp = ip; free (ip); --> Does jp or ip point to valid storage? Seperate Compilation ==================== Compilation process -------------------- [.c] -> Preprocessor -> C compiler -> Assember -> Linker -> Executable to run only the preprocessor use gcc -E C compiler use gcc -S assember use gcc -c linker use gcc to watch the whole process gcc -v hello.c Object files ------------ Object files contain code/data, symbols, debugging info. The object code of the compiler is split into three sections text ->actual code of functions data ->initialized data bss ->unitialized data Check this out with size file.o Symbol Tables ------------- names of external functions line numbers Check this out with utility nm Linking -------- Take a set of object files and create an executable file. main.o funs.o -------------------------------- extern void fun1(); void fun1() main() { { printf ("hi\n"); } fun1(); } Symbols T main T fun1() U fun1 T --> defined and given by object files U --> Refered and undefined. The program 'ld' is the linker. You should probably never use this directly. Other =========== Command line arguments ---------------------- The arguments are passed to the program as an array of strings. The 0 argument is always the name of the program. So argument 1 is array position 1. Example: void main(int argc, char **argv) { int cnt; printf ("I was invoked as %s\n", argv[0]); printf ("My arguments were:\n"); for (cnt=1; cnt < argc; cnt++) printf ("\t%d : %s\n", cnt, argv[cnt]); } Most programs take options like $ prog -v 1 txtfile But options are a pain... 1. See if the argument begins with - 2. Decode option (plus arguments to options) 3. Simpler way ------------ #include main(int argc, char **argv) { while ((c = getopt(argc, argv, "v:")) != EOF) switch (c){ case 'b': verbose = atoi (optarg); break; default: fprintf (stderr, "usage: prog [-v verbose_lvel] textfile\n"); exit (0); } printf ("argument was %s\n", argv[optind]); } review stdin/stdout + file IO/redirection ----------------------------------------- Every program starts with three FILE* pre-opened called: stdin --> The input stream stdout--> the output stream stderr--> A special output stream for errors These stream work like any opened file putc ('\n', stdout); fprintf (stdout, "....") == printf ("...."); The Shell is responsible for opening these files $ a.out Here's a shortened version of what is actually happining to launch your program. 1. Find the executable for the command (look in PATH) 2. Create a execution space 3. Open stdin/stdout/stderr for new space 4. load and execute file in new space. With file redirection, we can tell the shell what files/program should be opened. $ a.out < myfile # Open myfile instead of keyboard as stdin $ hello > log # Open log as stdout. Notice in this last example stderr still goes to the terminal window.