I. separate-compilation A. modularity ------------------------------------------ MODULARITY def: a program is *constructed modularly* if Economic benefits of modularity: Defining modular interfaces allows markets where suppliers can compete to supply module implementations. E.g., ------------------------------------------ ------------------------------------------ BENEFITS OF MODULARITY IN SOFTWARE Software is modular if it is Benefits: - separate compilation: - separate testing/verification - fault isolation: - suppliers can ------------------------------------------ B. How separate compilation is implemented in C (with gcc) 1. compile and link whole programs ------------------------------------------ COMPILATION A C compiler (gcc) turns If myprog.c is a whole program (including main), then: gcc myprog.c produces a.out Normally one uses -o option: gcc myprog.c -o myprog produces myprog (or myprog.exe on Windows) ------------------------------------------ 2. separate compilation of individual modules (files) Why would you want to save the results of compiling a single file? ------------------------------------------ SEPARATE COMPILATION IN C Use the -c option on gcc gcc -c to_roman.c produces ------------------------------------------ 3. linking ------------------------------------------ LINKING Linking: connects Example: Source files: to_roman.c checknum.c roman.c to_roman.h checknum.h Compiler command: gcc -c to_roman.c checknum.c roman.c produces: to_roman.o checknum.o roman.o Link via command: gcc to_roman.o checknum.o roman.o -o roman ------------------------------------------ 4. libraries ------------------------------------------ LIBRARIES def: a library is Example: the standard C library contains the functions defined in many headers: stdlib.h, stdio.h, string.h, math.h, ctype.h, errno.h float.h, limits.h, locale.h ... Example: the C math library contains: ------------------------------------------ II. Information Hiding in C A. information hiding ------------------------------------------ MODULES TERMINOLOGY Modules interface between: client code: implementation code: The interface is described by: ------------------------------------------ ------------------------------------------ INFORMATION HIDING def: *information hiding* means Examples of informtion hiding: ------------------------------------------ B. C language mechanisms for information hiding and export ------------------------------------------ C LANGUAGE MECHANISMS FOR INFO. HIDING Aside from macros, names in a C file are: hidden if they are: - declared inside functions (qualifier "auto", the default) - declared at the top level with exported to clients if they are: - top-level declarations with ------------------------------------------ 1. example ------------------------------------------ EXAMPLE MODULE stack module (stack.c and stack.h) stack.h declares (and specifies): #define MAX_STACK_SIZE 5000 extern void stack_push(int e); extern int stack_top(); extern void stack_pop(); extern int stack_size(); stack.c implements these functions using static int rep[MAX_STACK_SIZE]; static int sz = 0; Design decisions hidden: - - - ------------------------------------------ 2. example client ------------------------------------------ CLIENT OF STACK MODULE // file stackmain.c #include #include # include "stack.h" // compute 3*2 - (2+3) int main() { stack_push(3); int r1 = 2; int r2 = stack_top(); stack_pop(); stack_push(r1 * r2); stack_push(2); r1 = 3; r2 = stack_top(); stack_pop(); stack_push(r1 + r2); r2 = stack_top(); stack_pop(); r1 = stack_top(); stack_pop(); r2 = r1 - r2; printf("3*2 - (2+3) is %d\n", r2); return EXIT_SUCCESS; } ------------------------------------------ Do we have to change this client code if the implementation of stack changes? C. Data abstraction as a design principle ------------------------------------------ DATA ABSTRACTION def: *data abstraction* means Important because ------------------------------------------ What information is hidden by the stack module? D. scope rules for C ------------------------------------------ SCOPE RULES FOR C def: scope is the area of program text where In C the scope of a declaration extends from ------------------------------------------ Can already_included be used in main below: main() { /* ... */ } char already_included[500][100]; string_set_has(char s[]) { /* ... */ } Can it be used in string_set_has? 1. definition vs. declaration ------------------------------------------ C TERMINOLOGY: DECLARATION VS. DEFINITION def: a *declaration* introduces a name and its type (and other attributes) def: a *definition* is a declaration that either: - allocates storage or - implements a function example WHICH ONE? ======================================= int x; const int five = 5; extern int x; int inc(int x) { return x+1; } extern int inc(int x); ------------------------------------------ ------------------------------------------ MULTIPLE DEFINITIONS NOT ALLOWED It's illegal to have multiple definitions of a name in a program Why? ------------------------------------------ E. lifetimes: (storage classes, extent) ------------------------------------------ LIFETIMES OR STORAGE CLASSES IN C def: the *lifetime* (or dynamic extent) of a variable is ------------------------------------------ 1. infinite = whole program's execution (called static extent) ------------------------------------------ INFINITE LIFETIME (OR STATIC EXTENT) def: infinite lifetime is Properties: - initialized when program starts running - only one instance - default for functions and top-level definitions both extern and static Static variables in local scopes also have infinite lifetime e.g., seed in random number generator ------------------------------------------ 2. limited to activation of a function (called auto) ------------------------------------------ STACK ALLOCATED (OR AUTO) def: a stack-allocated variable has a lifetime that is Properties: - allocated on the run-time stack - more than one instance if have recursion - can be placed in registers! - default for function and block locals, and register vars ------------------------------------------ 3. initialization of variables ------------------------------------------ INITIALIZATION Variables can be initialized in their definitions Examples: int i = 0; double e = 2.73; Important for const variables const double pi = 3.14159; Important for locals with static extent static int seed = 64954; Initializers must be ------------------------------------------ Can initializer of an external variable involve a function call? Can initializer of an auto variable involve a function call? Should you use initialized declarations? ------------------------------------------ ARRAY INITIALIZATION Arrays can be initialized with a special form: int primes[] = {2, 3, 5, 7, 11, 13}; const char greeting[] = {'h', 'i', '!', '\0'}; // equivalent to the above const char greeting[] = "hi!"; ------------------------------------------ III. Friday problems with C modules A. rational numbers ------------------------------------------ FOR YOU TO DO Implement Rational Numbers, as specified by the following header file. // rational.h #ifndef RATIONAL_H #define RATIONAL_H 1 #include typedef int *ratl; /* requires: denom != 0; * ensures: result is a fresh rational number whose * numerator is num and denominator is denom */ extern ratl rmake(int num, int denom); // ensures: result is the numerator of r extern int numerator(ratl r); // ensures: result is the denominator of r extern int denominator(ratl r); // ensures: result is the sum of x and y extern ratl radd(ratl x, ratl y); // ensures: result is the arithmetic inverse of r extern ratl rnegate(ratl r); // ensures: result is the product of x and y extern ratl rmult(ratl x, ratl y); // requires: the numerator of r is not 0 // ensures: result is the multiplicative inverse of r extern ratl rinverse(ratl r); // ensures: result is true just when r1 and r2 are mathematically equal extern bool requals(ratl r1, ratl r2); #endif ------------------------------------------ ------------------------------------------ DESIGN DECISIONS - How to represent rationals? - How does the representation relate to the mathematical rationals? - Any other possibilities? ------------------------------------------ ------------------------------------------ IMPLEMENTING RMAKE #include "rational.h" #define ELEMS 2 ratl rmake(int num, int denom) { ------------------------------------------ How can we return our representation for a rational? ------------------------------------------ FOR YOU TO DO Implement the following functions: // ensures: result is the numerator of r extern int numerator(ratl r); // ensures: result is the denominator of r extern int denominator(ratl r); // ensures: result is the sum of x and y extern ratl radd(ratl x, ratl y); // ensures: result is the arithmetic inverse of r extern ratl rnegate(ratl r); // ensures: result is the product of x and y extern ratl rmult(ratl x, ratl y); // requires: the numerator of r is not 0 // ensures: result is the multiplicative inverse of r extern ratl rinverse(ratl r); // ensures: result is true just when r1 and r2 are mathematically equal extern bool requals(ratl r1, ratl r2); ------------------------------------------ B. complex numbers