Embedded C part 1. C programming and memory management

0 %
100 %
Information about Embedded C part 1. C programming and memory management

Published on February 22, 2014

Author: mohamedaly71653

Source: slideshare.net


This is first slide of series for embedded C programming.

Embedded C C programming and memory management

C programming

Compilation  C compilers take C and convert it into an architecture specific machine code (string of 1s and 0s) - Unlike other languages which convert to architecture independent code - Unlike other languages which interpret the code - These differ mainly in when your program is converted to machine instructions - For C, generally a 2 part process of compiling .c files to .o files, then linking the .o files into executables. Assembling is also done (but is hidden, i.e., done automatically, by default)

Compilation(cont.) Advantages  Great run-time performance - Generally much faster than other languages for comparable code (because it optimizes for a given architecture)  OK compilation time - Enhancements in compilation procedure (Makefiles) allow only modified files to be recompiled

Compilation(cont.) Disadvantages  All compiled files (including the executable) are architecture specific, depending on both the CPU type and the operating system.  Executable must be rebuilt on each new system. - Called “porting your code” to a new architecture  The “change  compile  run [repeat]” iteration cycle is slow

First program in C #include <stdio.h> /* function main begins program execution */ int main( void ) { printf( "Welcome to C! n" ); return 0; /* indicate that program ended successfully */ } /* end function main */

C program  C programs consist of pieces/modules called functions, exactly one of which must be main - A programmer can create his own functions • Advantage: the programmer knows exactly how it works • Disadvantage: time consuming - Programmers will often use the C library functions • Use these as building blocks - Avoid re-inventing the wheel • If a pre-made function exists, generally best to use it rather than write your own • Library functions carefully written, efficient, and portable

Comments  Text surrounded by /* and */ is ignored by compiler

#include  Preprocessor directive  Tells computer to load contents of a certain file  #include <stdio.h> - <stdio.h> allows standard input/output operations

printf  printf( "Welcome to C n" );  Instructs computer to perform an action - Specifically, prints the string of characters within quotes (" ")  Entire line called a statement - All statements must end with a semicolon ;  Escape character () - Indicates that printf should do something out of the ordinary - n is the newline character printf( "Welcome " ); printf( "to C n" ); Escape sequence Description n Newline. Position the cursor at the beginning of the next line. t Horizontal tab. Move the cursor to the next tab stop. a Alert. Sound the system bell. Backslash. Insert a backslash character in a string. " Double quote. Insert a double-quote character in a string.

scanf  scanf( "%d", &integer);  Obtains a value from the user - scanf uses standard input (usually keyboard)  This scanf statement has two arguments - %d indicates data should be a decimal integer - &integer location in memory to store variable - & is confusing in beginning - For now, just remember to include it with the variable name in scanf statements  When executing the program the user responds to the scanf statement by typing in a number, then pressing the enter key int integer; printf( "Enter first integern" ); scanf( "%d", &integer );

Variable declarations  All variable declarations must go before they are used (at the beginning of the block)  A variable may be initialized in its declaration; if not, it holds garbage  Examples of declarations: - correct: { int a = 0, b = 10; ... } - Incorrect: for (int i = 0; i < 10; i++)

Data/Variable types char unsigned int float  char – 1 byte - Sufficient to represent the local character set - Typically ASCII  int – signed integer values - Range dictated by natural word width of the machine  float – single precision floating point number - A lot like real numbers - Specific representation defined by IEEE  double – double precision floating point numb er - Even more like real numbers double

Bitwise and arithmetic operators  Computers provide direct hardware support for manipulating certain basic types A {&, |, ~, ^, <<, >>} Logical B Operations (Bitwise operation) B A B {+, -, *, /,%} Arithmetic Operations B  An attempt to divide by zero is normally undefined on computer systems and generally results in a fatal error  Bitwise operation are machine dependent - How will it deal with right shift for signed numbers?

Assignment operators  Assignment operators abbreviate assignment expressions c = c + 3; c += 3;  Examples of other assignment operators: - d -= 4 (d = d - 4) - e *= 5 (e = e * 5) - f /= 3 (f = f / 3) - g %= 9 (g = g % 9)

Increment and decrement operators • Increment operator (++) - Can be used instead of c+=1 • Decrement operator (--) - Can be used instead of c-=1 • Preincrement - Operator is used before the variable (++c or --c) - Variable is changed before the expression it is in is evaluated • Postincrement - Operator is used after the variable (c++ or c--) - Expression executes before the variable is changed

Increment and decrement operators(Cont.)  If c equals 5 printf( "%d", ++c ); /*Prints 6*/ printf( "%d", c++ ); /*Prints 5*/ /*In either case, c now has the value of 6*/ ++c; printf( “%d”, c ); c++; printf( “%d”, c ); /*In either case, c now has the value of 6 and prints 6*/

Logical operators  && ( logical AND ) - Returns true if both conditions are true  || ( logical OR ) - Returns true if either of its conditions are true  ! ( logical NOT, logical negation ) - Reverses the truth/falsity of its condition - Unary operator, has one operand  What evaluates to FALSE in C? – 0 (integer) – NULL (pointer: more on this later)  What evaluates to TRUE in C? – everything else…

Conditional operator (?:) printf( "%sn", grade >= 50 ? "Passed" : "Failed" ); grade >= 50 ? printf(“Passedn”) : printf(“Failed n”);

Equality and relational operators       =(Equal) !=(Not equal) >(Greater than) >=(Greater than or equal) <(Less than) <=(Less than or equal)

Do not mix  Do not be confused equality (==) and assignment (=) operators

Operators Associativity left to right highest right to left unary left to right multiplicative () [] + -- * / + - left to right additive << >> left to right shiting < <= left to right relational == != left to right equality left to right bitwise AND & . -> Type ++++ -% > >= ! & * ~ sizeof (type) Operator precedence and associativity. (Part 1 of 2.)

Operators Associativity Type ^ left to right bitwise OR | left to right bitwise OR && left to right logical AND || left to right logical OR ?: right to left conditional right to left assignment left to right comma = , += -= *= /= &= |= ^= <<= >>= %= Operator precedence and associativity. (Part 2 of 2.)

Where do variable live and work? 000..0: n: °°° FFF..F: Memory Processor register load operate store word

Functions return-value-type function-name( parameter-list ) { declarations and statements }      Function-name: any valid identifier Return-value-type: data type of the result (default int) - void – indicates that the function returns nothing Parameter-list: comma separated list, declares parameters - A type must be listed explicitly for each parameter unless, the parameter is of type int Definitions and statements: function body (block) - Variables can be defined inside blocks (can be nested) - Functions can not be defined inside other functions Returning control - If nothing returned return; or, until reaches right brace - If something returned return expression int square( int y ) { return y * y; } int x =10; Printf(“%0d”, square( x ) );

Functions(Cont.) Function prototype  Function name, Parameters, Return type  Used to validate functions  Prototype only needed if function definition comes after use in program #include<stdio.h> int square( int y ); int main( void ) { int x =10; Printf(“%d”, square( x ) ); return 0; } int square( int y ) { return y * y; }

Functions(Cont.) Calling functions  Call by value - Copy of argument passed to function - Changes in function do not effect original - Use when function does not need to modify argument (Avoids accidental changes)  Call by reference - Passes original argument - Changes in function effect original

Functions(Cont.) Recursive functions  Functions that call themselves  Can only solve a base case  Balance between performance (iterations/loops) and good coding style (recursion) long fibonacci( long n ) { if (n == 0 || n == 1) return n; else return fibonacci( n - 1) +fibonacci( n – 2 ); } Fibonacci series 0, 1, 1, 2, 3, 5, 8..

Functions(Cont.) Recursive functions(Cont.) Factorials 5! = 5 * 4 * 3 * 2 * 1 = 5 *(4!) long factorial( long number ) { if ( number <= 1 ) { return 1; } else { return ( number * factorial( number - 1 ) ); } }

Address vs. Value  Consider memory to be a single huge array: - Each cell of the array has an address associated with it. - Each cell also stores some value. - Do you think they use signed or unsigned numbers? Negative address?  Don’t confuse the address referring to a memory location with the value stored in that location. ... 101 102 103 104 105 ... 23 42 ...

Pointers  An address refers to a particular memory location. In other words, it points to a memory location.  Pointer: A variable that contains the address of a variable. Int * p = &x; P points to x Location (address) ... 101 102 103 104 105 ... 42 104 x name 23 y ... p Pointer to x

Pointers(Cont.)  How to create a pointer: & operator: get address of a variable int *p, x; x = 3; p ? x ? p ? x 3 Note the “*” gets used 2 different ways in this example. In the declaration to indicate that p is going to be a pointer, and in the printf to get the value pointed to by p. p p =&x; x 3 How get a value pointed to? * “dereference operator”: get value pointed to printf(“p points to %dn”,*p);

Pointers(Cont.)  How to change a variable pointed to? - Use dereference * operator on left of = p *p = 5; x 3 p x 5

Pointers(Cont.)  C pass parameters “by value” void addingOne (int x) { x = x + 1; } int main(void) { int y = 3; addingOne(y); /*y is still = 3*/ return 0; }

Pointers(Cont.)  How to get a function to change a value? void addingOne (int *p) { *p = *p + 1; } main { int y = 3; addingOne(&y); /*y is now = 4*/ }

Pointers(Cont.) Pointers dangers  Declaring a pointer just allocates space to hold the pointer – it does not allocate something to be pointed to!  What does the following code do? void f() { int *ptr; *ptr = 5; }

Pointers(Cont.) Pointers dangers(Cont.)  C lets you cast a value of any type to any other type without performing any checking int x = 1000; int *p = x; /* invalid */ int *q = (int *) x; /* valid */  The first pointer declaration is invalid since the types do not match.The second declaration is valid C but is almost certainly wrong - Is it ever correct?

Flow control statements  if-else  switch  for  while  do-while  goto  break  continue  Compound statements can be placed anywhere a single statement can be placed  It is a must to have at least single statement in their body, it is also possible to have no statement at all, i.e., the empty statement

Flow control statements(Cont.) if-else examples if ( grade >= 50 ) printf( "Passed. n"); else printf( "Failed. n"); if ( grade >= 50 ) printf( "Passed. n" ); else { printf( "Failed. n" ); printf( "You must take this course again. n" ); }

Flow control statements(Cont.) Nested if-else example if( grade >= 85 ) Printf( “Excellent n” ); else if( grade >= 75 ) printf( “Very Good n” ); else if( grade >= 65 ) printf( “Good n” ); else if( grade >= 50 ) printf( “Passed n” ); else printf( “Failed n” ); if( grade >= 85 ) Printf( “Excellent n” ); else if( grade >= 75 ) printf( “Very Good n” ); else if( grade >= 65 ) printf( “Good n” ); else if( grade >= 50 ) printf( “Passed n” ); else printf( “Failed n” );

Flow control statements(Cont.) switch statement case ‘v': ++vCount; break; case ‘g': ++gCount; break; case '‘p”: ++pCount; break; case 'n': case ' ': break; default: printf( "Incorrect letter grade entered. " ); printf( " Enter a new grade. n" ); break; switch statement anatomy switch ( variable ) { case ‘value_1': actions_1 case ‘value_2': actions_2 default: default_actions } switch ( grade ) { case ‘e': ++eCount; break; }

Flow control statements(Cont.) for loop initialization for ( initialization; loop-continuationTest; increment ) statement Initialization, loop-continuation test, and increment can contain arithmetic expressions. Loop Continuation Test No Yes statement increment int counter; for ( counter = 1; counter <= 10; counter++ ) { printf( "%dn", counter ); }

Flow control statements(Cont.) while examples int counter = 1; while ( counter <= 10 ) { printf( "%dn", counter ); ++counter; } counter = 0; while ( ++counter <= 10 ) printf( “%dn, counter ); int counter = 1; int result =1; while ( counter <= 10 ) { result = result * counter; counter = counter + 1; }

Flow control statements(Cont.) do-while example int counter = 0; do { printf( "%d ", counter ); } while (++counter <= 10);

Flow control statements(Cont.) goto statement  Unconditional branching to first statement after specified label  A label is an identifier followed by a colon label: /*Statement;*/ /*Compound statement*/ /*…………………………………*/ /*…………………………………*/ /*……..............................*/ /*Statement;*/ goto label;

Flow control statements(Cont.) break and continue statements  continue - Skips the remaining statements in the body of a while, for, or do…while statement in other words proceeds with the next iteration of the loop - For while and do…while, Loop-continuation test is evaluated immediately after the continue statement is executed - For for, Increment expression is executed, then the loopcontinuation test is evaluated  break - Causes immediate exit from a while, for, do…while or switch statement - Program execution continues with the first statement after the statement

Empty statement  The empty statement is represented by placing a semicolon (;) where a statement would normally be

Arrays  Ordered collection of objects of homogeneous type - “this string is also a array of chars” - {1, 2, 437, 61} 1 2 437 61

Arrays(Cont.)  Declaration: int ar[2]; - declares a 2-element integer array. int n[ 5 ] = { 1, 2, 3, 4, 5 }; - If not enough initializers, rightmost elements become 0 - If too many initializers, a syntax error occurs int ar[] = {795, 635}; - declares and fills a 2-element integer array.  Accessing elements: ar[num]; - returns the numth element. int ARRAY_SIZE = 10; int I; int a[ARRAY_SIZE]; int result = 0; for(i = 0; i < ARRAY_SIZE; i++) { result = result + a[i]; }

Arrays(Cont.) Where do arrays reside?  Arrays are stored in memory  The variable (i.e., name) is associated with the location (i.e., address) of the collection - Just like any basic variable  Elements are stored consecutively 000..0: A: °°° FFF..F:

Arrays(Cont.)  An array in C does not know its own length, & bounds not checked - We can accidentally access off the end of an array - So we must pass the array and its size to a procedure which is going to traverse it - This may lead to very difficult to find errors like segmentation faults and bus errors Please, Be careful!!! int ar[10], *p, *q, sum = 0; p = &ar[ 0]; q = &ar[10]; while (p != q) sum += *p++; /* sum = sum + *p; */ /* p = p + 1; */ /*WILL THIS LEAD TO ERROR?*/  No, this will not lead to error  C defines that one element past end of array must be a valid address

Segmentation fault and bus error  Segmentation fault - Running program attempts to access memory not allocated to it - Running program terminates with a segmentation violation error  Bus error - Processor detecting an anomalous condition on its bus - Such conditions include invalid address alignment (accessing a multi-byte number at an odd address), accessing a physical address that does not correspond to any device, or some other device-specific hardware error. - A bus error triggers a processor-level exception which may lead to terminate the running programm

Arrays(Cont.) 000..0: s: char *s; s = "abc"; * ‘a’ ‘b’ ‘c’ 0 °°° FFF..F: s is a reference to the string “abc” s is a pointer to the string “abc”

Arrays(Cont.) int main( void ) { char * c = "abc"; char ac [4] = "def"; printf("c[1]=%cn",c[1] ); printf("ac[1]=%cn",ac[1] ); return 0; } 000..0: c: * ‘c’ 0 °°° ‘e’ ‘f’ 0 ‘a’ ‘b’ ac: ‘d’  Array name is essentially the address of (readonly pointer to) the zeroth object in the array  Arrays are (almost) identical to pointers  There are a few subtle differences - Can change what c refers to, but not what ac refers to

Arrays(Cont.) Array of pointers  Arrays can contain pointers int *arrofptrs[ 4 ] = { {1,2}, {3,4}, {5,6}, {7,8}}; arrofptrs arrofptrs[0] [0] 1 2 3 4 5 6 7 8 arrofptrs[1] [1] arrofptrs[2] [2] arrofptrs[3] [3]

Multiple-subscripted arrays  Multiple subscripted arrays are used to describe tables/matrices with rows and columns (m by n matrix) int b[ 2 ][ 2 ] = { { 1, 2 }, { 3, 4 } };  Initializers grouped by row in braces  If not enough, unspecified elements set to zero printf( "%d", b[ 0 ][ 1 ] );  C interprets a[ x, y ] as a[ y ], and as such it does not cause a syntax error.

Arrays(Cont.) Passing arrays to functions  Function prototype void modifyArray( int arrayName[], int arraySize ); - Parameter names optional in prototype  Passing arrays - To pass an array argument to a function, specify the name of the array without any brackets int myArray[ 24 ]; modifyArray( myArray, 24 ); - Arrays passed call-by-reference  Passing array elements - Passed by call-by-value - Pass subscripted name (i.e., myArray[ 3 ]) to function

Arrays(Cont.) Passing arrays to functions(Cont.)  An array parameter can be declared as an array or a pointer; an array argument can be passed as a pointer. int strlen(char s[]) { int n = 0; while (s[n] != 0) n++; return n; } Can be written: while (s[n]) int strlen (char *s) { int n = 0; while (s[n] != 0) n++; return n; } Can be written: while (s[n])

Pointers operators  Arithmetic operations can be performed on pointers - Increment/decrement pointer (++ or --) - Add an integer to a pointer( + or += , - or -=) - Pointers may be subtracted from each other - Operations meaningless unless performed on an array - More about this later  Pointer comparison ( <,<=, == , != , >,>=)  Pointers of the same type can be assigned to each other - If not the same type, a cast operator must be used - Exception: pointer to void (type void *) • Generic pointer, represents any type • No casting needed to convert a pointer to void pointer • void pointers can not be dereferenced

Pointers operators(Cont.)  Since a pointer is just a memory address, we can add to it to traverse an array  (p+1) returns a pointer to the next array element  x = *++p; /*p = p + 1 ; x = *p ;*/  (*p++) versus ((*p)++) - x = *p++; /* x = *p ; p = p + 1; */ /* (*p++) ? *(p)++ ? *(p++) */ - x = (*p)++; /* x = *p ; *p= *p + 1; */  In reality, p+1 doesn’t add 1 to the memory address, it adds the size of the array element int get(int array[], int n) { return (array[n]); /* This is euivalent to return *(array + n); */ }

Pointers operators(Cont.) How many of the following are invalid? pointer + integer integer + pointer pointer + pointer pointer – integer integer – pointer pointer – pointer compare pointer to pointer compare pointer to integer compare pointer to 0 compare pointer to NULL

Pointers operators(Cont.) Question int main( void) { int A[] = {5,10}; int *p = A; printf(“%u %d %d %dn”,p,*p,A[0],A[1]); p = p + 1; printf(“%u %d %d %dn”,p,*p,A[0],A[1]); p = *p + 1; printf(“%u %d %d %dn”,p,*p,A[0],A[1]); } 5 10 A[0] A[1] p  If the first printf outputs 100 5 5 10, what will the other two printf outputs? a) 101 10 5 10 then 101 11 5 11 b) 104 10 5 10 then 104 11 5 11 c) 101 <other> 5 10 then 101 <3-others> d) 104 <other> 5 10 then 104 <3-others> e) One of the two printfs causes an ERROR

Pointers operators(Cont.) Example: Copying arrays void copy (int *from, int *to, int n) { int i; for(i=0; i<n; i++) { *to++ = *from++; } } 1st time looping 2nd time looping 3rd time looping Assume N=3; from to 10 ? 20 30 ? ?

Pointers operators(Cont.) Example  Sometimes we want to have a procedure increment a variable? void AddOne(int x) { x = x + 1; } Int main(void) { int y = 5; AddOne( y); printf(“y = %dn”, y); return 0; } “Y=5” gets printed Why!!! Because x tokes a copy of y but it has not any access to y itself

Pointers operators(Cont.) Example(Cont.) void AddOne(int * x) { *x = *x + 1; } Int main(void) { int y = 5; AddOne( &y); printf(“y = %dn”, y); return 0; } “Y=6” gets printed Why!!! Because x tokes a copy of y address so it has access to y itself

Pointers operators(Cont.) Example(Cont.) void IncrementPtr (int *p) { p = p + 1; } int main(void) { int A[3] = {50, 60, 70}; int *q = A; IncrementPtr(q); printf(“*q = %dn”, *q); } “*q = 50” gets printed A q 50 Why!!! p 60 70 Because p tokes a copy of q and p has access to content of address referenced by q but it has not any access to q itself

Pointers operators(Cont.) Example(Cont.) void IncrementPtr (int **p) { *p = *p + 1; } int main(void) { int A[3] = {50, 60, 70}; int *q = A; IncrementPtr(&q); printf(“*q = %dn”, *q); } *q = 60 A q 50 Why!!! *P 60 70 p *P Because p tokes a copy of q address so it has access to q itself

Pointers operators(Cont.)  So what’s valid pointer operations? - Add an integer to a pointer. - Subtract 2 pointers (in the same array). - Compare pointers (<, <=, ==, !=, >, >=) - Compare pointer to NULL (indicates that the pointer points to nothing).  Everything else is illegal since it makes no sense: - adding two pointers - multiplying pointers - subtract pointer from integer

Pointers pros and cons  Why use pointers? - If we want to pass a huge array, it’s easier and faster to pass a pointer than the whole thing - In general, pointers allow cleaner, more compact code  So what are the drawbacks? - Pointers are probably the single largest source of bugs in software, so be careful anytime you deal with them - Wilding reference: wild pointer which are not initialized during its definition holding some junk value( a valid address) are Wild pointer. - Dangling reference (premature free) A dangling pointer is a (Non NULL) pointer that points to invalid data or to data which is not valid anymore - Memory leaks (tardy free) a memory leak happen when an object is stored in memory but cannot be accessed by the running code

Pointers and allocation  After declaring a pointer, pointer doesn’t actually point to anything yet (it actually points somewhere - but don’t know where!)  We can either: - make it point to something that already exists - allocate room in memory for something new that it will point to…

Pointers and allocation(Cont.)  Pointing to something that already exists: int *ptr, var1, var2; var1 = 5; ptr = &var1; var2 = *ptr;  var1 and var2 have room implicitly allocated for them. ptr ? var1 ? 5 var2 ? 5

sizeof operator  C has operator sizeof() which gives size in bytes of type or variable  Assume size of objects can be misleading and is bad style, so use sizeof(type)  sizeof knows the size of arrays  As well knows for arrays whose size is determined at run-time

Dynamic memory allocation  To allocate room for something new to point to, use malloc()  malloc takes number of bytes to allocate(sizeof) and returns pointer of type void * . If no memory available, it returns NULL ptr = (int *) malloc (sizeof(int)); - Now, ptr points to a space somewhere in memory of size (sizeof(int)) in bytes  malloc is almost never used for 1 variable ptr = (int *) malloc (n*sizeof(int)); - This allocates an array of n integers

Dynamic memory allocation(Cont.)  Once malloc() is called, the memory location contains garbage, so do not use it until you have set its value.  After dynamically allocating space, we must dynamically free it  free deallocates memory allocated by malloc  free takes a pointer to memory that will be deallocated as an argument free(ptr);  The program frees all memory on exit (or when main returns), don't be lazy - You never know when your main will get transformed into a subroutine

Dynamic memory allocation(Cont.)  The following two things will cause your program to crash or behave strangely later on, and cause very hard to figure out bugs - freeing the same piece of memory twice - calling free() on something you didn't get back from malloc()  The runtime does not check for these mistakes - The Memory allocation is so performance-critical that there is not time to do this - The usual result is that you corrupt the memory allocator's internal structure - You won't find out until much later on, in a totally unrelated part of your code!!

Dynamic memory allocation(Cont.) calloc( nmembers, size );  nmembers – number of elements  size – size of each element  Returns a pointer to a dynamic array, each of size  initializes contents of memory to zeroes  Zeroing out the memory may take a little time, so you probably want to use malloc() if that performance is an issue  Allocated memory may/may not be contiguous

Dynamic memory allocation(Cont.) realloc( pointerToObject, newSize )  pointerToObject – pointer to the object being reallocated  newSize – new size of the object  Returns pointer to reallocated memory  Returns NULL if cannot allocate space  If newSize equals 0 then the object pointed to is freed  If pointerToObject equals 0 then it acts like malloc

How to overcome dangling pointers and wild pointers?  Initialize pointer variable to NULL  After deallocating memories initialize pointer to NULL  Take care or out of scope pointers (Block/Function)

String  A string in C is just an array of characters char string[] = "abc";  How do you tell how long a string is? - Last character is followed by a 0 byte (null terminator)  One common mistake is to forget to allocate an extra byte for the null terminator  More generally, C requires the programmer to manage memory manually - When creating a long string by concatenating several smaller strings, the programmer must insure there is enough space to store the full string - What if you don’t know ahead of time how big your string will be? - Buffer overrun security holes

String(Cont.) Standard functions  int strlen(char *string); - computes the length of string  int strcmp(char *str1, char *str2); - returns 0 if str1 and str2 are identical (how is this different from str1 == str2?)  char *strcpy(char *dst, char *src); - copies the contents of string src to the memory at dst. The caller must ensure that dst has enough memory to hold the data to be copied.

Structure  A struct is a data structure composed from simpler data types struct point { int x; int y; }; void PrintPoint(struct point p) { printf(“(%d,%d)”, p.x, p.y); } int main(void) { struct point p1 = {0,10}; PrintPoint(p1); }

Structure(Cont.) Where do structures reside?  struct are stored in memory  The variable (i.e., name) is associated with the location (i.e., address) of the collection  Elements are stored at fixed offsets - Can locate each of the elements  Can operate on the named member object just like an object of that type 000..0: S: °°° FFF..F:

Structure(Cont.)  Comparing of structures are not allowed  Usually, more efficient to pass a pointer to the struct  The C arrow operator (->) dereferences and extracts a structure field with a single operator  The following are equivalent: struct point *p; /* code to assign to pointer */ printf(“x is %dn”, (*p).x); printf(“x is %dn”, p->x);

Structure(Cont.)  A pointer to structure can be defined inside itself which is called recursive definition(Self-referential)  note that we can not define structure inside itself, why? struct Node { char *value; struct Node *next; }; Recursive definition

Structure(Cont.) Memory Example Struct processor { Alu a; memory m; bus b; peripheral p; Register * r; Processor coprocessor; Int num_reg; }; Void main(int) { Processor my_processor; } . . Memory overflow

Structure(cont.) How big are structs?  Recall C operator sizeof() which gives size in bytes (of type or variable) struct p { char x; int y; };  How big is sizeof(p)? 5 bytes? 8 bytes?  Compiler may word align integer y

Structures(Cont.) Bit fields     Bit field is member of a structure whose size (in bits) has been specified Bit field enables better memory utilization but what about performance Bit field does not enalbe us to access individual bits To define bit fields, Follow unsigned or int member with a colon (:) and an integer constant representing the width of the field struct Example { unsigned a : 13; unsigned b : 3; unsigned c : 4; }; struct Example2 { unsigned a : 13; unsigned b : 3; unsigned : 4; };  Unnamed bit field used as padding in the structure and nothing may be stored in these bits  Unnamed bit field with zero width aligns next bit field to a new storage unit boundary  Attempting to take the address of a bit field may not be applicable

Unions time Memory that contains a variety of objects over   Conserves storage but what about performance union Number { int x; float y; }; union Number value;  The amount of storage required to store a union is implementation dependent but will always be at least as large as the largest member of the union  Valid union operations - Assignment to union of same type: = - Taking address: & - Accessing union members: . - Accessing members using pointers: -> - Comparing unions is not allowed

typedef  Creates synonyms (aliases) for previously defined data types typedef struct Card *CardPtr;  Defines a new type name CardPtr as a synonym for type struct Card *  typedef does not create a new data type, only creates an alias

Where does the program itself reside?  In memory, just like the data  Processor contains a special 000..0: register – PC 0020FAC0: - Program counter - Address of the instruction 00401B20: to execute (i.e. ptr)  Instruction Execution Cycle FFF..F: - Instruction fetch - Decode - Operand fetch - Execute - Result Store - Update PC n: main: °°° Instruction Fetch Execute PC

Pointers to functions  Function name is starting address of code that defines function  Similar to how array name is address of first element  What is a pointer to a function? - A pointer just like any other - Data pointed at by the pointer is actually machine code for the function pointed at.  How is it declared? int (*f)(int start,int stop);  This declares a variable f which is a pointer to a function that returns an int and takes two ints as parameters  Now, just like any other pointer, the declaration does no allocation  So, in this case, f points at nothing and any attempt to dereference it will have very spectacular side effects!  You cannot dynamically allocate memory for function pointers

Pointers to functions(Cont.)   You can only set pointer-to-function variables equal to pointers to existing functions. How do you do that? int SimpleAdd(int arg1,int arg2) { return arg1 + arg2; } int main() { int (*f)(int start,int stop); f = SimpleAdd; return 0; }

Pointers to functions(Cont.)   We can call it! How do you call a function when you have a pointer to it int SimpleAdd(int arg1,int arg2) { return arg1 + arg2; } int main() { int (*f)(int start,int stop); f = SimpleAdd; int x = (*f)(3,4); int y = f(3,4); printf( “x is %d “,x); return 0; }

Pointers to functions(Cont.)      OK, interesting concept. But what use is it? Most frequently used to allow a programmer to pass a function to another function Suppose I am writing a function which contains variables which need to be acted on Suppose that I want to be able to have multiple ways to act on those variables A function pointer as a parameter is a good solution

Pointers to functions(Cont.) Examples char **argv; Argv : pointer to char Int (*daytab)[13]; daytab: pointer to array[13] of int int *daytab[13]; daytab: array[13] of pointer to int void *comp(); comp: function returning pointer to void void (*comp)(); comp: pointer to function returning void char (*(*x())[])(); x: function returning pointer to array[] of pointer to function returning char char (*(*x[3])())[5]; x: array[3] of pointer to function

Global variable  So far we have talked about several different ways to allocate memory for data: 1. Declaration of a local variable 2. “Dynamic” allocation at runtime by calling allocation function (alloc).  One more possibility exists… 3. Data declared outside of any procedure (i.e., before main). - Similar to #1 above, but has “global” scope. int myGlobal; main() { }

Storage classes and scope rules  Visibility vs Lifetime  Variables declared within a function - Arguments and Local Variables - Visible in remainder of function - Lifetime = Function Call - Each call obtains a new set of variables • Recursive calls too - C “internals”  Variables declared outside any function - Visible in remainder of file (!!!) • include .h file • extern vs static - Lifetime = Whole Program - C “externals”  Malloc’d objects int ave(int A, int B) { int C = (A + B)/2; return C; } int count = 0; int fib(int n) { count++; if (n <= 2) return 1; return fib(n-1)+fib(n-2); }

Storage classes and scope rules(Cont.) Storage classes  Automatic storage - Object created and destroyed within its block - auto: default for local variables auto double x, y; - register: tries to put variable into high-speed registers • Can only be used for automatic variables register int counter = 1;  Static storage - Variables exist for entire program execution - Default value of zero - static: local variables defined in functions. • Keep value after function ends • Only known in their own function - extern: default for global variables and functions • Known in any function

Storage classes and scope rules(Cont.) Scope rules  File scope - Identifier defined outside function, known in all functions - Used for global variables, function definitions, function prototypes  Function scope - Can only be referenced inside a function body - Used only for labels (start:, case: , etc.)  Block scope - Identifier declared inside a block • Block scope begins at definition, ends at right brace - Used for variables, function parameters (local variables of function) - Outer blocks "hidden" from inner blocks if there is a variable with the same name in the inner block  Function prototype scope - Used for identifiers in parameter list

const qualifier • const qualifier – Variable cannot be changed – Use const if function does not need to change a variable – Attempting to change a const variable produces an error • const pointers – Point to a constant memory location – Must be initialized when defined int *const myPtr = &x; /*constant pointer to an int*/ const int *myPtr = &x; /*Modifiable pointer to a const int*/ const int *const Ptr = &x; /*const pointer to a const int*/ /*x itself can be changed, but not *Ptr*/

Preprocessor directives  Preprocessing occurs before a program is compiled  Lines begin with #  Only whitespace characters before directives on a line

Preprocessor directives(Cont.) #include  Copy of a specified file included in place of the directive  #include <filename> searches standard library for file  #include "filename" searches current directory, then standard library

Preprocessor directives(Cont.) #define  Preprocessor directive used to create symbolic constants and macros #define identifier replacement-text  Everything to right of identifier replaces text  Symbolic constants: When program compiled, all occurrences of symbolic constant replaced with replacement text  Cannot redefine symbolic constants once they have been created #define PI 3.14159 #define PI = 3.14159

Preprocessor directives(Cont.) #define(Cont.)  Macro is an operation defined in #define  A macro without arguments is treated like a symbolic constant  macro with arguments has its arguments substituted for replacement text, when the macro is expanded  Performs a text substitution – no data type checking #define CIRCLE_AREA( r ) ( PI * ( r ) * ( r ) ) area = CIRCLE_AREA( 4 ); area = ( 3.14159 * ( 4 ) * ( 4 ) );

Preprocessor directives(Cont.) #define(Cont.)  Use parentheses #define CIRCLE_AREA( r) PI * r * r area = CIRCLE_AREA( c + 2 ); area = 3.14159 * c + 2 * c + 2;  Multiple arguments #define RECTANGLE_AREA( x, y ) ( ( x ) * ( y ) rectArea = RECTANGLE_AREA( a + 4, b + 7 ); rectArea = ( ( a + 4 ) * ( b + 7 ) );  Macros(inline function/code) eliminates the overhead of a function call but what about memory usage  #undef undefines a symbolic constant or macro  If a symbolic constant or macro has been undefined it can later be redefined

Preprocessor directives(Cont.) #define(Cont.)  Predefined symbolic constants cannot be used in #define or #undef Symbolic constant Explanation __LINE__ The line number of the current source code line (an integer constant). __FILE__ The presumed name of the source file (a string). __DATE__ The date the source file was compiled (a string of the form "Mmm dd yyyy" such as "Jan 19 2002"). __TIME__ The time the source file was compiled (a string literal of the form "hh:mm:ss"). __STDC__ The value 1 if the compiler supports Standard C. Some predefined symbolic constants.

Preprocessor directives(Cont.) Conditional compilation #if !defined( NULL ) #define NULL 0 #endif  Cast expressions, sizeof, enumeration constants cannot be evaluated in preprocessor directives  #elif – equivalent of else if in an if statement  #else – equivalent of else in an if statement  Every #if must end with #endif  #ifdef short for #if defined( name )  #ifndef short for #if !defined( name )  We can use it for commenting out code or for debugging purpose

Preprocessor directives(Cont.) #error and #pragma #error tokens  Tokens are sequences of characters separated by spaces  #error displays a message including the specified tokens as an error message  #error stops preprocessing and prevents program compilation #pragma tokens  #pragma is for compiler directives that are machine-specific or operating-system-specific  It tells the compiler to do something, set some option, take some action, override some default, etc. that may lead to unportability

#line  Renumbers subsequent code lines, starting with integer value  File name can be included #line 100 "myFile.c"  Lines are numbered from 100 beginning with next source code file  Compiler messages will think that the error occurred in "myfile.C"

assert macro  Header <assert.h>  Tests value of an expression  If 0 (false) prints error message and calls abort, terminating the program execution assert( x <= 10 );  If NDEBUG is defined all subsequent assert statements ignored #define NDEBUG

# operator  # causes a replacement text token to be converted to a string surrounded by quotes #define HELLO( x ) printf( “Hello, ” #x “n” ); HELLO( John ) /*printf( “Hello, ” “John” “n” );*/

## operator  ## concatenates two tokens #define TOKENCONCAT( x, y ) x ## y TOKENCONCAT( O, K )

C keywords Keywords auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while

C memory management

C memory management  C has 3 pools of memory - Static storage: global variable storage, basically permanent, entire program run - The Stack: local variable storage, parameters, return address - The Heap (dynamic storage): data lives until deallocated by programmer  C requires knowing where objects are in memory, otherwise things don’t work as expected

Normal C memory management(Cont.) ~ FFFF FFFFhex  A program’s address space contains 4 regions: - Stack grows downward - Heap resizes dynamically, grows upward - Static data does not grow or shrink - Code loaded when program starts, does not change stack heap static data code ~ 0hex For now, OS somehow prevents accesses between stack and heap .

Stack  Stack frame includes: - Return “instruction” address - Parameters - Space for other local variables SP  Stack frames contiguous blocks of memory; stack pointer tells where top stack frame is  When procedure ends, stack frame is tossed off the stack; frees memory for future stack frames frame frame frame frame

Stack(Cont.)  Last In, First Out (LIFO) data structure stack main () { a(0); } void a (int m) { b(1); } void b (int n) { c(2); } void c (int o) { d(3); } void d (int p) { } Stack Stack Pointer grows down Stack Pointer Stack Pointer Stack Pointer Stack Pointer

Stack(Cont.) Example int *ptr () { int y; y = 3; return &y; } main () { int *stackAddr,content; stackAddr = ptr(); content = *stackAddr; printf("%d", content); /* 3 */ content = *stackAddr; printf("%d", content); /*13451514 */ } main SP SP ptr() (y==3) main main SP printf() (y==?)

Heap  Large pool of memory, not allocated in contiguous order - back-to-back requests for heap memory could result blocks very far apart  In C, specify number of bytes of memory explicitly to allocate item - malloc() allocates raw, uninitialized memory from heap and returns type (void *)

Heap(Cont.) Heap management requirements  Want malloc() and free() to run quickly.  Want minimal memory overhead  Want to avoid fragmentation when most of our free memory is in many small chunks - In this case, we might have many free bytes but not be able to satisfy a large request since the free bytes are not contiguous in memory. * This is technically called external fragmentation

Heap(Cont.) Heap management  An example - Request R1 for 100 bytes - Request R2 for 1 byte - Memory from R1 is freed - Request R3 for 50 bytes R1 (100 bytes) R2 (1 byte)

Heap(Cont.) Heap management(Cont.)  An example - Request R1 for 100 bytes - Request R2 for 1 byte - Memory from R1 is freed - Request R3 for 50 bytes R3? R2 (1 byte) R3?

Heap(Cont.) malloc/free implementation  Each block of memory is preceded by a header that has two fields: size of the block and a pointer to the next block  All free blocks are kept in a circular linked list, the pointer field is unused in an allocated block  malloc() searches the free list for a block that is big enough. If none is found, more memory is requested from the operating system. If what it gets can’t satisfy the request, it fails.  free() checks if the blocks adjacent to the freed block are also free - If so, adjacent free blocks are merged into a single, larger free block - Otherwise, the freed block is just added to the free list

Heap(Cont.) Allocation policies  If there are multiple free  Best-fit: Tries to limit blocks of memory that are fragmentation but at the cost of time (must examine big enough for some all free blocks for each request, how do we malloc). Leaves lots of small choose which one to use? - best-fit: choose the smallest block that is big enough for the request - first-fit: choose the first block we see that is big enough - next-fit: like first-fit but remember where we finished searching and resume searching from there blocks (why?)  First-fit: Quicker than bestfit (why?) but potentially more fragmentation. Tends to concentrate small blocks at the beginning of the free list (why?)  Next-fit: Does not concentrate small blocks at front like first-fit, should be faster as a result.

Intel 80x86 C memory management  A C program’s 80x86 address space heap static data ~ 08000000hex code stack

Breaking the abstraction  Attack - Cause the OS (or service or application) to do things it should not - Pass unterminated strings, bad length paramters, bad ptrs - Corrupting system data may cause it to do other harm  “Smashing the stack” - Send bad mesg causing system code to overwrite parts of its stack • Local vars and return address • Bad return - OS or app starts executing out of stack as if it were instructions - Message contains jump instructions to send it off to attacker code 0000000: reserved 0040000: 1000000: code <= instructions static data <= externs 1008000: heap <= malloc RA 7FFFFFFF: FFFFFFFF: stack unused <= Local variables <= OS, etc.

References  “ the c programming language”,2nd edition , Brian W.Kernighan and Dennis M.Richie , Pearson Education .  “Operating Systems Concepts “, 7th Edition Silbershatz , Galvin, Gagne  “MODERN OPERATING SYSTEMS”, SECOND EDITION, Andrew S.Tanenbaum

thanks Embedded systems

Add a comment

Related presentations

Related pages

Mastering stack and heap for system reliability: Part 1 ...

... Dynamic Memory Management ... Mastering stack and heap for system reliability: Part 1 ... Embedded Systems Programming / Embedded Systems Design ...
Read more

Memory-oriented optimization techniques for dealing with ...

... with memory-oriented programming and compiler techniques. Part 1: ... Memory is a key bottleneck in embedded systems ... from c[i ][j ] to c[i ][j + 1].
Read more

Programming and optimizing C code, part 1 | EE Times

Programming and optimizing C code, part 1. ... For more programming tips, ... C also assumes a large flat memory model.
Read more

C Memory Management - Stack Overflow

... an example of when you would have to do some "memory management ... C embedded and games ... part of memory management, ...
Read more

C programming for embedded system applications

C programming for embedded ... memory • Data types, constants, variables ... if bit 7 of PORTA is 1. c = PORTB & 0x04; ...
Read more

Visual C#.NET, Part 1: Introduction to Programming Languages

Visual C#.NET, Part 1: Introduction to Programming Languages. Learn today what you need to get started with Visual C#.NET. We'll be taking a look at the ...
Read more

FreeRTOS - Memory management options for the FreeRTOS ...

Memory Management [More Advanced] ... (heap_1.c , heap_2.c, heap_3.c ... { /* Start address of a block of memory that will be part of the heap.*/ uint8_t ...
Read more

Micro-Controller Operating Systems - Wikipedia, the free ...

Micro-Controller Operating Systems ... memory management, and for timing. [1 ... in a three-part article in Embedded Systems Programming magazine and ...
Read more

C (programming language) - Wikipedia, the free encyclopedia

... embedded C programming requires ... Kernighan and Ritchie say in the Introduction of The C Programming Language: "C, ... Memory management ...
Read more


Swissbit is the only independent embedded memory and storage ... 38 PArt NumberS Swissbit memory (1) ... S L N 08G 64 e 2b DSA c * r t 1 2 3 4 5 6 7 8 9 10 ...
Read more