I. Separate Compilation ------------------------------------------ SEPARATE COMPILATION Which is better? a. 1 file with 500 lines of code b. 7 files with 500 lines of code Why? ------------------------------------------ A. declarations vs. definitions ------------------------------------------ DECLARATIONS AND DEFINITIONS def: a *declaration* describes a name's def: a *definition* describes Declaration examples: extern int somefun(); int from_roman(char *num); static int three(); extern int counter; struct complex { double x, y; }; enum sign {positive, zero, negative}; typedef struct { double r,theta;} cmplx; Definition examples: int somefun() { return three(); } int from_roman(char* num) { int val = 0; /* ... */ return val; } static int three() { return 3; } int counter; struct complex coordinates; enum sign the_sign = positive; cmplx i; ------------------------------------------ 1. Rules for declarations and definitions ------------------------------------------ RULES FOR DECLARATIONS AND DEFINITIONS There must be only There can be The *scope* of a declaration extends ------------------------------------------ Why is only one definition allowed for a name? a. forward declarations ------------------------------------------ FORWARD DECLARATIONS NEEDED IN C What does a compiler say about: void parseExpr() { /* ... */ parseTerm(); /* ... */ } void parseTerm() { /* ... */ parseExpr(); /* ... */ } How to fix it? ------------------------------------------ 2. simultaneous declaration and definition ------------------------------------------ SIMULTANEOUS DECLARATION AND DEFINITION For local variables and functions not used elsewhere: Example: Every definition is also a declaration ------------------------------------------ B. Compiler options 1. default: compile and link a complete program ------------------------------------------ DEFAULT COMPILATION: ENTIRE PROGRAM gcc sayHelloProgram.c produces an executable in a.out What if there are multiple .c files? ------------------------------------------ How does this work? ------------------------------------------ EXAMPLE ENTIRE PROGRAM // file sayHelloProgram.c #include #include extern void sayHello(); extern const char *who(); int main(int argc, char *argv[]) { sayHello(); return EXIT_SUCCESS; } void sayHello() { printf("Hello, %s!\n", who()); } const char *who() { return "class"; } ------------------------------------------ How do you compile and link this into an executable program, when all the code is contained in "sayHelloProgram.c"? 2. saving results of file compilation Why would you want to save the results of compiling a single file? a. example i. main module ------------------------------------------ // FILE sayHelloMain.c #include #include "sayHello.h" int main(int argc, char *argv[]) { sayHello(); return EXIT_SUCCESS; } ------------------------------------------ Why doesn't this main program need to include ? ii. sayHello module ------------------------------------------ // FILE sayHello.h #ifndef _SAYHELLO_H #define _SAYHELLO_H extern void sayHello(); #endif // FILE sayHello.c #include #include "sayHello.h" #include "who.h" void sayHello() { printf("Hello, %s!\n", who()); } ------------------------------------------ Why does sayHello.h not need to include stdio.h? Why does sayHello.c include sayHello.h? Why does sayHello.c need to include "who.h"? iii. who module ------------------------------------------ // FILE who.h /* $Id: who.h,v 1.1 ... */ #ifndef _WHO_H #define _WHO_H extern const char *who(); #endif // FILE who.c /* $Id: who.c,v 1.2 ... */ #include "who.h" const char *who() { return "class of modular programmers"; } ------------------------------------------ b. separate compilation of the example ------------------------------------------ SEPARATE COMPILATION Compile each .c file to an object file: gcc -c sayHelloMain.c sayHello.c who.c Use the -c option to ------------------------------------------ c. using the Unix "make" tool ------------------------------------------ UNIX MAKE TOOL Rules in a file named "makefile" (or "Makefile") Makefile rules: # macros, definitions of names CC = gcc CFLAGS = -g -std=c17 -Wall OBJECTS = sayHelloMain.o sayHello.o who.o sayHelloMain.o: sayHelloMain.c sayHello.h $(CC) $(CFLAGS) -c sayHelloMain.c %.o: %.c %.h $(CC) $(CFLAGS) -c $< sayHello: $(OBJECTS) $(CC) $(CFLAGS) -o sayHello \ $(OBJECTS) ------------------------------------------ What would happen if we give the compiler the same .o file twice? 3. linking ------------------------------------------ LINKING def: *linking* brings together several separately compiled files into one executable Commands that do linking: ld, gcc What it does: ------------------------------------------ II. Information Hiding in C A. Modularity 1. Examples in Real Life ------------------------------------------ EXAMPLES OF MODULARITY IN REAL LIFE Electric plugs, can plug in anything: - toaster, - TV - computer - phone charger - coffee maker Cooking ingredients: - meat (chicken, etc.) - butter - fruits - spices What makes a system modular? ------------------------------------------ What other examples of modular systems are there? Does a modular system allow for competition? If you are selling gasoline, do you need customers who understand all of its properties and how it was made? How much do you want and need to know about the gasoline you buy? 2. Examples in software ------------------------------------------ EXAMPLES OF MODULARITY IN SOFTWARE SQL queries work on: - many different databases - on many kinds of computers - same meaning everywhere TCP/IP network protocol: - connects many different systems (different hardware, different OS) - clients include: browsers, email, ... Mathematical libraries: - computation of trig. functions - on many different computers - approximately same results ------------------------------------------ What other examples are there of modularity in software? 3. software terminology a. roles: client and implementation ------------------------------------------ MODULARITY IN SOFTWARE 2 roles: - client: - implementation: Agreed upon interface: - names and how they can be used ------------------------------------------ Does an API allow for different implementations? If there is a standard API, what can change? b. modules ------------------------------------------ MODULES IN PROGRAMMING A module: In programming want to hide decisions about: ------------------------------------------ 4. information hiding ------------------------------------------ INFORMATION HIDING Some information Ideally, information about decisions that are likely to change e.g.: ------------------------------------------ What are some examples of changing decisions? 5. Programming Language Support a. kinds of language support ------------------------------------------ PROG. LANG. SUPPORT FOR INFORMATION HIDING Limit clients: - discovery of secrets - manipulation of secrets - creation of secrets Mechanisms: - function mechanisms - scope limitations - export/import of names - type limitations ------------------------------------------ b. information hiding in C ------------------------------------------ INFO. HIDING IN C Modules are Names private to module: Names available to clients: ------------------------------------------ ------------------------------------------ EXAMPLE IN C: SET OF STRINGS // FILE string_set.h #ifndef _STRING_SET_H #define _STRING_SET #include // Initialize the string set extern void string_set_init(); // Put s into the set extern void string_set_add(const char *s); // Is s in the set? extern bool string_set_has(const char *s); // ... #endif ------------------------------------------ How could we implement this API? ------------------------------------------ ONE IMPLEMENTATION // FILE string_set.c #include #include #include #include #include "string_set.h" typedef struct element_s { const char *val; struct element_s *next; } element; static element *elements; // invariant: elements is // a singly-linked list with no cycles // invariant: no duplicates // in the list of elements // Initialize the string set void string_set_init() { elements = NULL; } // Put s into the set void string_set_add(const char *s) { if (!string_set_has(s)) { // s is not already in the list element *newelem = malloc(sizeof(element)); if (newelem == NULL) { fprintf(stderr, "No space!\n"); exit(EXIT_FAILURE); } newelem->val = s; newelem->next = elements; elements = newelem; } assert(string_set_has(s)); } // Is s in the set? extern bool string_set_has(const char *s) { element *p = elements; while (p != NULL) { if (strcmp(p->val, s) == 0) { return true; } p = p->next; } return false; } // ... ------------------------------------------ What is hidden in this implementation? Can clients make the invariant untrue? What is exported by this implementation? Are there any other modules that this code is using? 6. Abstract Data Type ------------------------------------------ ABSTRACT DATA TYPES def: an *abstract data type* (ADT) is Benefits: ------------------------------------------ What are the drawbacks of using ADTs?