INC 161 Computer Programming for INC Lecture 7

  • Slides: 33
Download presentation
INC 161 Computer Programming for INC Lecture 7 Preprocessing Directive & Program Structure

INC 161 Computer Programming for INC Lecture 7 Preprocessing Directive & Program Structure

Introduction • Preprocessing – Affect program preprocessing and execution – Capabilities • Inclusion of

Introduction • Preprocessing – Affect program preprocessing and execution – Capabilities • Inclusion of additional C source files • Definition of symbolic constants and macros • Conditional preprocessing of a program • Format of preprocessing directives A preprocessing directive consists of a sequence of preprocessing tokens that begins with a pound sign #, which must be the first non-space character on the line. Some preprocessing directives are listed below. # is for preprocessing directives (macro)

These commands are not changed to machine code.

These commands are not changed to machine code.

Code with macro Substitute code Cut code (with macro) C Code Change to machine

Code with macro Substitute code Cut code (with macro) C Code Change to machine Language (compile) Machine Language

Symbolic Constants and Macros • The #define Preprocessing Directive – This preprocessing directive is

Symbolic Constants and Macros • The #define Preprocessing Directive – This preprocessing directive is used to create symbolic constants and macros. • Form #define identifier replacement-list defines an object-like macro that causes each subsequent instance of the macro names to be replaced by the replacement-list of preprocessing tokens that constitute the remainder of the directive. The new-line is a character that terminates the #define preprocessing directive.

 • Symbolic constants The simple form of macro is particularly useful for introducing

• Symbolic constants The simple form of macro is particularly useful for introducing named constants into a program. It allows for easier modification of the constants later on. When programs are processed, all occurrences of symbolic constants indicated by identifier are replaced by the replacement-list. Example: #define BLOCK_SIZE 0 x 100 we can write int size = BLOCK_SIZE; instead of int size = 0 x 100; in the program. Note: Cannot redefine symbolic constants with different values by multiple #define statements

 • A preprocessing directive of the form #define identifier(identifier-list-opt) replacement-list new-line defines a

• A preprocessing directive of the form #define identifier(identifier-list-opt) replacement-list new-line defines a function-like macro with arguments, similar syntactically to a function call. The parameters are specified by the optional list of identifiers. Example: if a macro mul with two arguments is defined by #define mul(x, y) ((x)*(y)) then the source program line result = mul(5, a+b); is replaced with result = ((5)*(a+b));

NOTE: Parentheses are important in macro definitions. Example: If macro mul is defined as

NOTE: Parentheses are important in macro definitions. Example: If macro mul is defined as #define mul(x, y) (x*y) The statement result = mul(5, a+b); in the source program becomes result = (5*a+b); The evaluation will be incorrect.

 • #undef – Undefine a symbolic constant or macro, which can later be

• #undef – Undefine a symbolic constant or macro, which can later be redefined. Example: #define mul(x, y) ((x)*(y)) /* … */ #undef mul int mul; /* mul can be used after it is undefined */

Source File Inclusion • The #include Preprocessing Directive – Copy of a specified header

Source File Inclusion • The #include Preprocessing Directive – Copy of a specified header file included in place of the directive. It has following two common forms. 1)#include <header. h> – Searches standard library for header file and replaces the directive by the entire contents of the file. – In Ch, the header is searched according to the paths specified by the system variable _ipath. C compilers in Unix will typically search the header file in the directory /usr/include. In Visual C++, the header file is searched based on the paths in the environment variable INCLUDE. or cl –I C: /home/assount/include program. c – Used for standard library files 2) #include “header. h" – C compilers and interpreters will first search the header file in the same directory where the file is being processed, which typically is the current directory. – Then search the header file in the paths as if it was included by #include <header. h>.

 • Applications – Loading header files #include <stdio. h> – Programs with multiple

• Applications – Loading header files #include <stdio. h> – Programs with multiple source files to be compiled together – Includes user defined header files which have common declarations and definitions (classes, structures, function prototypes, and macros)

Conditional Compilation • Conditional compilation – Enables the user to control the compilation of

Conditional Compilation • Conditional compilation – Enables the user to control the compilation of the program, screen out portions of source code that are not to be compiled. • Structure – The structure is similar to if and else statement in C. • Conditional preprocessing directives – #if, #else, #elif, and #endif

 • Preprocessing directives of the forms #if expr 1 /*. . . */

• Preprocessing directives of the forms #if expr 1 /*. . . */ #elif expr 2 /*. . . */ #else /*. . . */ #endif check whether the controlling expression evaluates to nonzero. Every #if ends with #endif Example: #if defined(_HPUX_) printf(“I am using HP-UXn”); #elif defined(_WIN 32_) printf(“I am using Windowsn); #endif

 • Preprocessing directives of the forms # ifdef # ifndef identifier check whether

• Preprocessing directives of the forms # ifdef # ifndef identifier check whether the identifier is or is not currently defined as a macro name. – #ifdef identifier is the short form of #if defined(identifier) – #ifndef identifier is the short form of #if !defined(identifier) • • Each directive’s condition is checked in order. If it evaluates to false (zero), then the group that it controls is skipped: directives are processed only through the name that determines the directive in order to keep track of the level of nested conditionals. Only the first group whose control condition evaluates to true (nonzero) is processed. If none of the conditions evaluates to true, and there is a #else directive, then the group controlled by the #else is processed; if lacking a #else directive, then all the groups until the #endif are skipped.

 • Debugging code #define DEBUG /*. . . */ double x; x =

• Debugging code #define DEBUG /*. . . */ double x; x = some_func(); #ifdef DEBUG printf(“The value of x = %fn”, x); #endif – Defining DEBUG to print out the value of x. – After debugging, remove #define statement. The debugging statements are ignored.

 • To include a header file in a program only once, it is

• To include a header file in a program only once, it is typically handled using the combination of the following preprocessing directives #ifndef, #define, and #endif. For example, a header file header. h may consist of the following code fragment. #ifndef HEADER_H #define HEADER_H /* code */ #endif

test. c #include <stdio. h> #include “add. h” add. h int add(int x, int

test. c #include <stdio. h> #include “add. h” add. h int add(int x, int y) …. add(1, 2); printf(“test”) …. #include <stdio. h> int add(int x, int y) { { …. printf(“add”) …. main() { total } …. printf(“add”) …. } main() { …. add(1, 2); printf(“test”) …. } }

Program 1: /* File: accelmacro. c */ #include <stdio. h> #define M_G #define FORCE(t)

Program 1: /* File: accelmacro. c */ #include <stdio. h> #define M_G #define FORCE(t) #define ACCEL(p, mu, m) 9. 81 (4*(sin(t)-3)+20) (((p)-(mu)*(m)*M_G)/(m)) int main() { double a, p, mu, m, t; mu = 0. 2; m = 5. 0; t = 2. 0; p = FORCE(t); a = ACCEL(p, mu, m); // or a = ACCEL(FORCE(t), mu, m); printf("Acceleration a = %f (m/s^2)n", a); return 0; } Output: Acceleration = 1. 364823 (m/s^2)

Program 2: /* File: #include /* local #include accelhead. c */ <stdio. h> header

Program 2: /* File: #include /* local #include accelhead. c */ <stdio. h> header file */ "accel. h" int main() { /* declare variables */ double a, mu, m, t; /* Initialize variables */ mu = 0. 2; m = 5. 0; t = 2. 0; /* File: accel. h */ #ifndef ACCEL_H #define M_G /* processing */ a = accel(t, mu, m); 9. 81 double force(double t); double accel(double t, double mu, double m); #endif /* display the output and termination */ printf("Acceleration a = %f (m/s^2)n", a); return 0; } double force(double t) { double p; p = 4*(sin(t)-3)+20; return p; } double accel(double t, double mu, double m) { double a, p; p = force(t); a = (p-mu*m*M_G)/m; return a; }

Global and Local Variables Although it is not recommended, global variables shared by different

Global and Local Variables Although it is not recommended, global variables shared by different functions can be used to communicate between functions. The same identifiers can be used in different scopes. The values of the variables are stored in different memory locations.

Example global Output: g g in in func 1() = 11 func 2() =

Example global Output: g g in in func 1() = 11 func 2() = 12 func 3() = 1 main() = 12 /* File: global. c */ #include <stdio. h> int g = 10; // global variable void func 1(void) { g++; printf("g in func 1() = %dn", g); } void func 2(void) { g++; printf("g in func 2() = %dn", g); } void func 3(void) { int g=0; // local variable g is the same is all functions because it is a global variable g++; printf("g in func 3() = %dn", g); } int main() { func 1(); func 2(); func 3(); printf("g in main() = %dn", g); return 0; }

Example local Output: g is different when it is in different {. . }

Example local Output: g is different when it is in different {. . } pair /* File: local. c */ #include <stdio. h> void func 1(void) { int g = 1; //try removing this line later g++; printf("g in func 1() = %dn", g); } int main() { int g = 1; printf("g in main before func 1() = %dn", g); func 1(); printf("g in main after func 1() = %dn", g); return 0; }

Scope of Identifiers The scope of an identifier is the portion of the program

Scope of Identifiers The scope of an identifier is the portion of the program in which the identifier can be accessed. There are four types of scope: program scope, file scope, function scope, and block scope. – Program scope. The identifiers having a program scope are accessible among different files. Variables with program scope are called global variables. – File scope. The identifiers having a file scope are active from its declaration point to to the end of the file. The global static variables have a file scope. – Function scope. The identifiers having a function scope are active from the beginning to the end of the function. The variables declared at the beginning of a function have a function scope. – Block scope. A block is a bunch of statements enclosed in braces. The identifiers having a block scope is active from its declaration point to the end of the block in which it is declared. The variables declared inside a block have a block scope.

Scope of Identifiers Program Scope File Scope Function Scope Block Scope

Scope of Identifiers Program Scope File Scope Function Scope Block Scope

Example: Output: program_i in main() = 10 file_i in main() = 20 program_i in

Example: Output: program_i in main() = 10 file_i in main() = 20 program_i in func() = 10 file_i in func() = 20 function_i in func() = 30 program_i in block = 10 file_i in block = 20 function_i in block = 30 block_i in block = 40 /* File: scopeid. c */ #include <stdio. h> int program_i = 10; /* extern int otherfile_i; if otherfile_i is declared in other file */ static int file_i = 20; void func(void) { int function_i = 30; printf("program_i in func() = %dn", program_i); printf("file_i in func() = %dn", file_i); printf("function_i in func() = %dn", function_i); { int block_i = 40; printf("program_i in block = %dn", program_i); printf("file_i in block = %dn", file_i); printf("function_i in block = %dn", function_i); printf("block_i in block = %dn", block_i); } } int main() { printf("program_i in main() = %dn", program_i); printf("file_i in main() = %dn", file_i); func(); return 0; }

Storage Class C provides four storage classes indicated by the storage-class specifiers. The valid

Storage Class C provides four storage classes indicated by the storage-class specifiers. The valid storage-class specifiers are given in the following table. Specifier Function auto or register local automatic variable static variable external variable

auto or register: Keyword auto or register is used to declare variables of automatic

auto or register: Keyword auto or register is used to declare variables of automatic storage duration. The automatic storage duration is legal only for variables with block scope. Since this is the default storage type, the keyword auto or register is rarely used. static: Keyword static is used to declare variables of static storage duration inside or outside a function. For such a variable, storage is reserved and its stored value is initialized only once. The variable exists, has constant address, and retains its laststored value throughout the execution of the entire program. When the variable is declared inside a function, the keyword static makes a variable has static storage duration instead of the default automatic duration. For a variable declared outside a function, the keyword static gives the variable file scope instead of program scope. extern: The keyword extern is used to declare global variables which are defined either later in the same file or in a different file.

Static Variables Outside Function A variable declared outside function by the keyword static has

Static Variables Outside Function A variable declared outside function by the keyword static has file scope instead of program scope. In the following example, the static variable x and static function func 2() can only be accessed inside the file staticfile. c.

staticprog. c staticfile. c /* File: staticfile. c */ #include <stdio. h> /* File:

staticprog. c staticfile. c /* File: staticfile. c */ #include <stdio. h> /* File: staticprog. c */ #include <stdio. h> static int x = 10; /* declare static variable x */ static int func 2(void); /* declare static function func 2() */ /* add code from file staticfile. c */ #if defined(_CH_) #pragma importf <staticfile. c> #endif int func 1(void) { func 2(); printf("static x in func 1() x++; return 0; } /* declare extern function func 1() */ extern int func 1(void); /* declare global variable x; */ int x = 20; = %dn", x); static int func 2(void) { printf("static x in func 2() = %dn", x); x++; return 0; } int main() { printf("global x in main() = %dn", x); x++; func 1(); printf("global x in main() = %dn", x); return 0; } Output of staticprog. c global x in main() = 20 static x in func 2() = 10 static x in func 1() = 11 global x in main() = 21

Static Variables Inside a Function Local variables declared inside a function with the keyword

Static Variables Inside a Function Local variables declared inside a function with the keyword static have static duration. The difference between an automatic variable and a static local variable is that the latter retains its value even when the function is exited. When the function is called next time, the static local variable contains the value it had when the function exited last time. The following example illustrates this difference.

Example: /* File: staticf. c */ #include <stdio. h> int func(void) { // static

Example: /* File: staticf. c */ #include <stdio. h> int func(void) { // static variable x is initialized only once static int x=10; // automatic variable y is initialized // each time when func() is called. int y=10; printf("x = %d y = %dn", x, y); x++; y++; printf("x = %d y = %dn", x, y); return 0; } int main() { func(); return 0; } Output: x x = = 10 11 11 12 y y = = 10 11

External Variables and Functions The following example demonstrates how to use extern to declare

External Variables and Functions The following example demonstrates how to use extern to declare external variables and functions. The global variable x and function func 1() are defined in the file externfile. c. In order to access them in the file externprog. c, the keyword extern must be used to declare the external variable x and function func 1() in the file externprog. h.

externfile. h externfile. c /* File: externprog. h */ #ifndef EXTERNPROG_H #define EXTERNPROG_H /*

externfile. h externfile. c /* File: externprog. h */ #ifndef EXTERNPROG_H #define EXTERNPROG_H /* File: externfile. c */ #include <stdio. h> #include “externprog. h” /* declare extern int int x = 10; extern variable x */ x; extern function func 1(void) */ func 1(); /* load code from file externfile. c for Ch */ #if defined(_CH_) #pragma importf <externfile. c> #endif Output of externprog. c global x in main() = 10 global x in func 1() = 11 global x in main() = 12 /* declare global variable */ int func 1(void) { printf("global x in func 1() x++; return 0; } = %dn", x); externprog. c /* File: externprog. c */ #include <stdio. h> #include “externprog. h” int main() { printf("global x in main() = %dn", x); x++; func 1(); printf("global x in main() = %dn", x); return 0; }