compilation / pointers debugging 101. compilation in c/c++ hello.c preprocessor compiler stdio.h...
Post on 20-Dec-2015
226 views
TRANSCRIPT
Preprocesser
A single-pass program that Include header files Expands macros Control conditional compilation Remove comments
#include directive
#include ”foo.h” Include the file “foo.h”, from current directory
#include <stdio.h> Include the file “stdio.h” from the standard
library directory (part of compiler installation)
Modules & Header files
Complex.c
struct Complex { double _real, _imag;};Complex addComplex(Complex, Complex);Complex subComplex(Complex, Complex);...
complex.h
#include <math.h>#include “complex.h”
// implementationComplex addComplex(Complex a, Complex b){ …
complex.c
#include “complex.h”int main(){ Complex c; …
MyProg.c
Header files
Header file contain Definition of data types Declarations of functions & constants
That are shared by multiple modules.
#include directive allows several modules to share the same set of definitions/declarations
#define -- cautions
#define square(x) x*x
b = square(a+1);
c = square(a++);
Is it what we intended?
b = a+1*a+1;
// b = 2*a+1;
c = a++*a++;
// c = a*a; a+=2;
#define
#define directive should be used with caution
Alternative to macros: Constants
enum { FOO = 1; };
or
const int FOO = 1; Functions – inline functions (C++, later on)
#if directive
Allows to have conditional compilation#if defined(DEBUG)
// compiled only when DEBUG exists
printf(“X = %d\n”, X);
#endif
#if – header safety
Complex.h:struct Complex { …
MyStuff.h:#include “Complex.h”
Main.c#include “MyStuff.h”
#include “Complex.h”
Error:Complex.h:1: redefinition of `struct Complex'
#if – header safety
Complex.h (revised):#if !defined(COMPLEX_H)
#define COMPLEX_H
struct Complex {
…
#endif
Main.c:#include “MyStuff.h”
#include “Complex.h” // no error this time
Preprocessor
We can test what the preprocessor does
> gcc –E hello.c
will print the C code after running preprocess
assert.h#include <assert.h>
// Sqrt(x) - compute square root of x
// Assumption: x non-negative
double
Sqrt(double x )
{
assert( x >= 0 ); // aborts if x < 0
…
If the program violates the condition, thenassertion "x >= 0" failed: file "Sqrt.c", line 7
<exception>
The exception allows to catch the event in the debugger
assert.h
Important coding practice Declare implicit assumptions Sanity checks in code Check for violations during debugging/testing
Can we avoid overhead in production code?
assert.h#undef assert
// 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
Compilation
Takes input C-code and produces machine code (object file) gcc –c Main.c Main.c Main.o
The object file does not contain all external references It leaves names, such as “printf”,
“addComplex”, etc. as undefined references
Linking
Combines several object files into an executable file No unresolved references
Main
PreprocessorCompiler
Complex.c Complex.o
Main.c Main.o
Linker
libc.a
Link errors
The following errors appear only at link time Missing implementation> gcc -o Main Main.p
Main.o(.text+0x2c):Main.c: undefined reference to `foo'
Duplicate implementation> gcc -o Main Main.o foo.ofoo.o(.text+0x0):foo.c: multiple definition of `foo'
Main.o(.text+0x38):Main.c: first defined here
Memory Arrangement
Memory is arrange in a sequence of addressable units (usually bytes) sizeof( <Type> ) return the number of units
it takes to store a type. sizeof(char) = 1 sizeof(int) = 4 (on most of our machines)
Arrays
C does not provide any run time checks int a[4]; a[-1] = 0;
a[4] = 0;
This will compile and run (no errors)
…but can lead to unpredictable results. It is the programmer’s responsibility to check
whether the index is out of bounds…
Arrays
C does not provide array operations int a[4];
int b[4];
… a = b; // illegal
if( a == b ) // illegal
…
Array Initialization int arr[3] = {3, 4, 5}; // Good
int arr[] = {3, 4, 5}; // Good - The same
int arr[4] = {3, 4, 5}; // Good - The last is 0
int arr[2] = {3, 4, 5}; // Bad
int arr[2][3] = {{2,5,7},{4,6,7}}; // Good
int arr[2][3] = {2,5,7,4,6,7}; // Good - The same
int arr[3][2] = {{2,5,7},{4,6,7}}; // Bad
int arr[3];
arr = {2,5,7}; // Bad - array assignment only in initialization
Pointersint main()
{
int i,j;
int *x; // x points to an integer
i = 1;
x = &i;
j = *x;
x = &j;
(*x) = 3;i j x
1
Pointersint main()
{
int i,j;
int *x; // x points to an integer
i = 1;
x = &i;
j = *x;
x = &j;
(*x) = 3;i j x
10x0100
0x0100
Pointersint main()
{
int i,j;
int *x; // x points to an integer
i = 1;
x = &i;
j = *x;
x = &j;
(*x) = 3;i j x
10x0100
0x01001
Pointersint main()
{
int i,j;
int *x; // x points to an integer
i = 1;
x = &i;
j = *x;
x = &j;
(*x) = 3;i j x
10x0100
0x01041
Pointersint main()
{
int i,j;
int *x; // x points to an integer
i = 1;
x = &i;
j = *x;
x = &j;
(*x) = 3;i j x
10x0100
0x01043
Pointers
Declaration
<type> *p;
p points to objects of type <type> Pointer value
*p = x;
y = *p;
*p refers to the object p points to value pointer
&x - the pointer to x
Example – the swap functionDoes nothing Works
void swap(int a, int b){ int temp = a; a = b; b = temp;}….int main(){ int x, y; x = 3; y = 7; swap(x, y); // now x==3, y==7….
void swap(int *pa, int *pb){ int temp = *pa; *pa = *pb; *pb = temp;}….int main(){ int x, y; x = 3; y = 7; swap(&x, &y); // x == 7, y == 3…
Pointers & Arrays
int *p;
int a[4];
p = &a[0];
*(p+1) = 1; // assignment to a[1]!
p a[1] a[2] a[3]a[0]
Pointers & arrays
Arrays are essentially constant pointers int *p;
int a[4];
p = a; // same as p = &a[0]
p[1] = 102; // same as *(p+1)=102;
*(a+1) = 102; // same
p++; // p == a+1 == &a[1]
a = p; // illegal
a++; // illegal
Pointers & Arrays
int foo( int *p );
andint foo( int a[] );
Are declaring the same interface In both cases, a pointer to int is being passed
to the function foo
Pointer Arithmetic
int a[4]; int *p = a;
char *q = (char *)a; // Explicit cast
// p and q point to the same location
p++; // increment p by 1 int (4 bytes)
q++; // increment q by 1 char (1 byte)
a[1] a[2] a[3]a[0]
q p
Pointer arithmeticint FindFirstNonZero( int a[], int n )
{
int *p;
for( p = a; p < a+n && (*p) == 0; p++ )
;
return p-a;
}
Same as int FindFirstNonZero( int a[], int n )
{
int i;
for( i = 0; i < n && a[i] == 0; i++ )
;
return i;
}
void *
void *p defines a pointer to undetermined type
int j;
int *p = &j;
void* q = p; // no cast needed
p = (int*)q ; // cast is needed