1 Building a program in C: Preprocessor, Compilation and Linkage
Building a program in C – Reminder 2 Main Preprocessor, Compiler Main.c Main.o Linker libc.a
3 The Preprocessor
Preprocessor 4 A single-pass program that: 1. Include header files 2. Expands macros 3. Control conditional compilation 4. Remove comments Outputs – a code ready for the compiler to work on.
#include directive 5 #include "foo.h" Include the file “foo.h”, from current directory #include Include the file “stdio.h” from the standard library directory (part of compiler installation)
Modules & Header files 6 Complex.c int area (int x1,int y1, int x2, int y2);... square.h #include "square.h" #include // implementation int area (int x1,int y1,int x2, int y2) {... } square.c #include "square.h" int main() { area (2,3, 5,6); } MyProg.c
Header files 7 Header file contain 1. Definition of data types 2. Declarations of functions & constants 3. That are shared by multiple modules. #include directive allows several modules to share the same set of definitions/declarations
#define directive 8 #define FOO 1 int x = FOO; is equivalent to int x = 1;
#define with arguments 9 #define SQUARE(x) x*x b = SQUARE (a); is the same as b = a*a;
10 #define SQUARE (x) x*x b = SQUARE (a+1); c = SQUARE (a++); Is it what we intended? b = a+1*a+1; //Actually: b = 2*a+1; c = a++*a++; //Actually: c = a*a; a+=2; #define – cautions
11 #define SQUARE (x) ((x)*(x)) b = SQUARE (a+1); c = SQUARE (a++); Is it what we intended? b = ((a+1)*((a+1)); //Now ok c = ((a++)*(a++)); //Did not help: c = a*a; a+=2;
#define 12 #define directive should be used with caution! Alternative to macros: Constants enum { FOO = 1 }; or const int FOO = 1; Functions – inline functions (C99,C++)
#define 13 Multi-line: All preprocessor directive effect one line (not c statement). To insert a line-break, use “\”: BAD: #define x (5 + 5) // x == 10 ! GOOD : #define x (5 + \ 5) // x == 10 !
#if directive 14 Allows to have conditional compilation #if defined(DEBUG) // compiled only when DEBUG exists printf("X = %d\n", X); #endif
Preprocessor – summary 15 Text processing program. Does not know c rules Operates before compilation, output passed to compiler. Can do copy and paste / cut #include paste the included file here Commonly included file (.h by convention) contains forward declarations #define copy the macro body, paste it where macro name appears - constants, simple "functions" #if condition not fulfilled, cut the code - Conditional compilation – e.g. debugging code
16 vs Debug/Test mode vs Release mode
17 vs Debug/Test mode vs Release mode #include #define MAX_INTS 100 int main() { int ints[MAX_INTS]; // i should be in bounds, but is it really? i = foo( ); // safety assertions assert(i>=0); assert(i<MAX_INTS); ints[i] = 0;...
18 #include #define MAX_INTS 100 int main() { int ints[MAX_INTS]; // i should be in bounds, but is it really? i = foo( ); // safety assertions assert(i>=0); assert(i<MAX_INTS); ints[i] = 0;... vs Debug/Test mode vs Release mode
19 #include #define MAX_INTS 100 int main() { int ints[MAX_INTS]; // i should be in bounds, but is it really? i = foo( ); // safety assertions assert(i>=0); assert(i<MAX_INTS); ints[i] = 0;... #define NDEBUG
20 assert bad // bad, foo() will not be called // if the compiler removes the assert() // if NDEBUG is defined assert(foo() == 0); good // good int errCode = foo(); assert(errCode == 0);
21 Use for: Catching bugs Don't use for: checking malloc, user input,... assert
assert.h 22 #include // Sqrt(x) - compute square root of x // Assumption: x non-negative double sqrt(double x ) { assert( x >= 0 ); // aborts if x < 0 …
assert.h 23 // procedure that actually prints error message void __assert(char* file,int line,char* test); #ifdef NDEBUG #define assert(e) ((void)0) #else #define assert(e) \ ((e) ? (void)0 : \ __assert(__FILE__, __LINE__, #e)) #endif
assert.h 24 Important coding practice Declare implicit assumptions Sanity checks in code Check for violations during debugging/testing
25 Compilation
26 Translate the c code to machine code. Every machine architecture has a different code. Need separate compilation. x86 : older but still common PCs “32-bit” (Intel/AMD) x64 : newer PCs “64-bit” (Intel/AMD) ARM : (many versions) Phones, tablets (ARM) Translated code is an “executable” – the OS can load it to the machine memory, and the let the CPU do whatever you wrote in the code.
“Assembly” 27 int y=2; int mult(int x) { return x*y; mov eax,dword ptr [x] imul eax,dword ptr [ h] } int main() { return mult(5); push 5 call 11711A4h } Only part of the assembly code is shown here. Actually each command has binary code, and the sequence of these code is the object file.
Compiling warnings
29 Add “-Wall” flag to catch things like this: if (i=3) { //bug, we meant i==3 … }
Basic Data Types & Memory & Representation
Basic data types Primitive data types are similar to JAVA: char int short long float double Unlike in JAVA, All can be signed/unsigned Default: signed Unlike in JAVA, the types sizes are machine dependant! 31
Memory – few definitions Bit – a binary digit - zero or one Byte – 8 bits Not C specific 0/1 32
Basic data types The types sizes must obey the following rules. 1. Size of char = 1 byte 2. Size of short ≤ size of int ≤ size of long Undetermined type sizes Advantage: hardware support for arithmetic operations Disadvantage: problems with porting code from one machine to another 33
signed VS. unsigned Each type could be signed or unsigned int negNum = -3; int posNum = 3; unsinged int posNum = 3; unsinged int posNum = -3; 34
Integers binary representation 35