C Programming Language Review Language Review: 1 Embedded Systems
C Programming Language Review Language Review: 1 Embedded Systems
Language Review
Embedded Systems 1
C: A High-Level Language
Gives symbolic names to values
– don’t need to know which register or memory location
Provides abstraction of underlying hardware
– operations do not depend on instruction set
– example: can write “a = b * c”, even if
CPU doesn’t have a multiply instruction
Provides expressiveness
– use meaningful symbols that convey meaning
– simple expressions for common control patterns (if-then-else)
Enhances code readability
Safeguards against bugs
– can enforce rules or conditions at compile-time or run-time
Embedded Systems 2
A C Code “Project”
• You will use an “Integrated Development Environment”
(IDE) to develop, compile, load, and debug your code.
• Your entire code package is called a project. Often you
create several files to spilt the functionality:
– Several C files
– Several include (.h) files
– Maybe some assembly language (.src) files
– Maybe some assembly language include (.inc) files
Embedded Systems 3
Compiling a C Program
C
Entire mechanism is usually called Source and
Header Files
the “compiler”
Preprocessor
– macro substitution C Preprocessor
– conditional compilation
– “source-level” transformations
Compiler
• output is still C
Source Code
Compiler Analysis
Linker
– combine object files
(including libraries) Library
Linker
Object Files
into executable image
Executable
Image
Embedded Systems 4
Compiler
Source Code Analysis
– “front end”
– parses programs to identify its pieces
• variables, expressions, statements, functions, etc.
– depends on language (not on target machine)
Code Generation
– “back end”
– generates machine code from analyzed source
– may optimize machine code to make it run more efficiently
– very dependent on target machine
Symbol Table
– map between symbolic names and items
– like assembler, but more kinds of information
Embedded Systems 5
Memory Map for Our MCU
Embedded Systems 6
Classifying Data
Variables
– Automatic – declared within a function
• Only exist while the function executes
• Are re-initialized (re-created, in fact) each time the function is called
– Static – declared outside of all functions, always exist
• Can make an automatic variable retain its value between invocations
by using the “static” keyword
Embedded Systems 7
Storage of Local and Global Variables
int inGlobal;
void chapter12() {
int inLocal;
int outLocalA;
int outLocalB;
/* initialize */
inLocal = 5;
inGlobal = 3;
/* perform calculations */
outLocalA = inLocal++ & ~inGlobal;
outLocalB = (inLocal + inGlobal) - (inLocal -
inGlobal);
}
Embedded Systems 8
Another Example Program with Function Calls
const int globalD=6;
int compute(int x, int y);
int squared(int r);
void main() {
// These are main’s automatic variables, and will be
int a, b, c; a = 10; // stored in main’s frame
b = 16;
c = compute(a,b);
}
int compute(int x, int y) {
int z;
z = squared(x);
z = z + squared(y) + globalD;
return(z);
}
int squared(int r) {
return (r*r);
}
Embedded Systems 9
Control Structures
• if – else
• switch
• while loop
• for loop
Embedded Systems 10
If-else
if (condition)
action_if;
else T F
condition
action_else;
action_if action_else
Embedded Systems 11
Switch
switch (expression) { evaluate
case const1: expression
action1; break;
case const2:
action2; break; = const1? action1
default: T
action3; F
}
= const2? action2
T
F
action3
Alternative to long if-else chain.
If break is not used, then
case "falls through" to the next.
Embedded Systems 12
While
while (test)
loop_body;
F
test
T
loop_body
F
test
T
loop_body
Executes loop body as long as
test evaluates to TRUE (non-zero).
Initialization and re-initialization re-init
code included in loop statement.
Embedded Systems 15
Masking
One of the most common uses of logical operations is “masking.”
Masking is where you want to examine only a few bits at a time, or
modify certain bits.
For example, if I want to know if a certain number is odd or even, I can
use an “and” operator.
0101 0101 0101 0101
AND 0000 0000 0000 0001
0000 0000 0000 0001
Or, lets say you want to look at bits 7 to 2:
0101 0101 0101 0101
AND 0000 0000 1111 1100
0000 0000 0101 0100
Embedded Systems 16
Code Example
Let’s assume three switches
connected to port 1 like the
following:
SW1
SW2
After you set the direction:
SW3
int data;
data = (int)PORT1.PIDR.BIT.B0;
Embedded Systems 17
C examples
Now, write the C code to interrogate
the switches and print
“Switch n pressed”
if it is being pressed. Print
“No switches pressed”
SW1
SW2
SW3
If none are being pressed.
Embedded Systems 19
1D Arrays
Embedded Systems 20
2D Arrays
Columns
[0][0] [0][1] [0][2]
Rows
Embedded Systems 21
Pointers
A pointer variable holds the address of the data, rather void main ( ) {
than the data itself int i, j;
To make a pointer point to variable a, we can specify int *p1, *p2;
the address of a 1 i = 4;
– address operator & 2 j = 3;
The data is accessed by dereferencing (following) the 3 p1 = &i;
pointer 4 p2 = &j;
– indirection operator * works for reads and writes 5 *p1 = *p1+*p2;
Assigning a new value to a pointer variable changes 6 p2 = p1;
where the variable points, not the data }
1&2 3 4 5 6
Adx
i 4 600 i 4 i 4 i 7 i 7
j 3 602 j 3 j 3 j 3 j 3
p1 604 p1 600 p1 600 p1 600 p1 600
p2 608 p2 p2 602 p2 602 p2 600
Embedded Systems 22
More about Pointers
Incrementing and decrementing pointers to array elements
– Increment operator ++ makes pointer advance int a[18];
to next element (next larger address) int * p;
– Decrement operator -- makes pointer move to p = &a[5];
previous element (next smaller address) *p = 5; /* a[5]=5 */
– These use the size of the variable’s base type p++;
(e.g. int, char, float) to determine what to add *p = 7; /* a[6]=7 */
• p1++ corresponds to p1 = p1 + sizeof(int); p--;
• sizeof is C macro which returns size of type
*p = 3; /* a[5]=3 */
in bytes
Embedded Systems 23
What else are pointers used for?
Data structures which reference each other
– lists
– trees
– etc.
Exchanging information between procedures
– Passing arguments (e.g. a structure) quickly – just pass a pointer
– Returning a structure
Accessing elements within arrays (e.g. string)
Embedded Systems 24
Strings
See Section 16.3.4 of Patt & Patel.
There is no “string” type in C.
Instead an array of characters is used - char a[44]
The string is terminated by a NULL character (value of 0,
represented in C by \0).
– Need an extra array element to store this null
Example
– char str[10] = “testing”;
t e s t i n g \0
str
str[0]
str[1] str[2]
Embedded Systems 25
Formatted String Creation
Common family of functions defined in stdio.h
– printf: print to standard output
– sprintf: print to a string
– fprintf: print to a file
Syntax: sprintf(char *str, char * frmt, arg1, arg2, arg3 .. );
– str: destination
– fmt: format specifying what to print and how to interpret arguments
• %d: signed decimal integer
• %f: floating point
• %x: unsigned hexadecimal integer
• %c: one character
• %s: null-terminated string
– arg1, etc: arguments to be converted according to format string
Embedded Systems 26
sprintf Examples – strings and integers
char s1[30], s2[30];
int a=5, b=10, c=-30;
char ch=‘$’; s1
sprintf(s1, “Testing”); Testing
s2
sprintf(s2, “a=%d, b=%d”, a, b); a=5, b=10
s1
sprintf(s1, “b=%x, c=%d”, b, c); b=a, c=-30
s1
sprintf(s1, “b=0x%x”, b); b=0xa
s2
sprintf(s2, “s1=%s”, s1); s1=b=0xa
s1
sprintf(s1, “%c %c”, ch, s2); $s
Embedded Systems 27
sprintf Examples – floating-point
Variation on %f format specifier
– %-w.pf
• - = left-justify. Optional
• w = minimum field width (# of symbols)
• p = precision (digits after decimal point)
Examples
Embedded Systems 28
sprintf Examples – More Integers
Variation on %d format specifier for integers (d/i/o/x/u)
– %-w.pd
• - = left justify. Optional
• w = minimum field width (# of symbols)
• p = precision (digits). Zero pad as needed
Examples
int a=442, b=1, c=-11; s1
char s1[30], s2[30];
442
sprintf(s1, “%5d”, a);
s1
sprintf(s1, “%-4d”, b); 1
s1
sprintf(s1, “%4d”, b); 1
s1
sprintf(s1, “%-5.4d”, c);
-011
Embedded Systems 29
String Operations in string.h
Copy ct to s including terminating null character. Returns a pointer to s.
– char* strcpy(char* s, const char* ct);
s1 = “cheese”;
s2 = “limburger”;
strcpy(s1, s2); /* s1 = limburger */
Embedded Systems 30
More String Operations
Concatenate at most n characters of ct to s. Terminate s with the null
character and return a pointer to it.
– char* strncat(char* s, const char* ct, int n);
s1 = “cheese”;
s2 = “ puffs”;
strncat(s1, s2, 4); /* cheese puf */
Embedded Systems 31
More String Operations
Return pointer to first occurrence of c in s1, or NULL if not found.
– char* strchr(const char* s1, int c);
s1 = “Smeagol and Deagol”;
char a *;
a = strchr(s1, “g”); /* returns pointer to s1[4] */
Embedded Systems 32
Dynamic Memory Allocation in C
Why?
– Some systems have changing memory requirements, and stack
variables (automatic) aren’t adequate
– Example: Voice recorder needs to store recordings of different lengths.
Allocating the same size buffer for each is inefficient
How?
– Allocate nbytes of memory and return a start pointer
• void * malloc (size_t nbytes);
– Allocate nelements*size bytes of memory and return a start pointer
• void * calloc (size_t nelements, size_t size);
– Change the size of a block of already-allocated memory
• void * realloc (void * pointer, size_t size);
– Free a block of allocated memory
• void free (void * pointer);
Embedded Systems 33
Using Dynamic Memory Management
Request space for one or more new variables
– Request pointer to space for one element
int * j, *k;
j = (int *) malloc (sizeof(int));
*j = 37;
– Request pointer to space for array of elements and initialize to zero
k = (int *) calloc(num_elements, sizeof(int));
k[0] = 55;
k[1] = 31;
– These return NULL if there isn’t enough space
• Program has to deal with failure -- embedded program probably
shouldn’t just quit or reset….
Free up space when done using variables
free(k);
Embedded Systems 34
Example Application: Voice Recorder A
Recording
– While record switch is pressed buffer record
• sample microphone record
record
• store in temporary RAM buffer delete
– When record switch is released
• copy audio to a permanent buffer
• add to end of list of recordings
Playback and skipping
– forward switch: skip forward over one recordings
recording, wrap around at end
– play switch: play the current recording
– delete switch: delete the current
recording
Data Structure: linked list of recordings
Embedded Systems 35
Data Structure Detail: Linked List
Each list element is defined as a
typedef struct {
structure with fields
unsigned AudioSize;
– AudioSize: Number of bytes
char * AudioData;
– AudioData: … struct List_T * Next;
– Next: Pointer to next list element } List_T;
Embedded Systems 36
Code for Voice Recorder main
unsigned char buffer[MAX_BUFFER_SIZE];
struct List_T * recordings = NULL, * cur_recording = NULL;
void main(void) {
while (1) {
while (NO_SWITCHES_PRESSED)
;
if (RECORD)
handle_record();
else if (PLAY)
handle_play();
else if (FORWARD)
handle_forward();
else if (DELETE)
handle_delete();
}
}
Embedded Systems 37
Code for handle_forward
void handle_forward(void) {
if (cur_recording)
cur_recording = cur_recording->Next;
if (!cur_recording)
cur_recording = recordings;
}
Embedded Systems 38
Code for handle_record
void handle_record(void) {
unsigned i, size;
unsigned char * new_recording;
struct List_T * new_list_entry;
i = 0;
while (RECORD)
buffer[i++] = sample_audio();
size = i;
new_recording = (unsigned char *) malloc (size);
for (i=0; i<size; i++) /* could also use memcpy() */
new_recording[i] = buffer[i];
new_list_entry = (List_T *) malloc ( sizeof(List_T) );
new_list_entry->AudioData = new_recording;
new_list_entry->AudioSize = size;
new_list_entry->Next = NULL;
recordings = Append(recordings, new_list_entry);
}
Embedded Systems 39
Code for handle_delete
void handle_delete(void) {
List_T * cur = recordings;
if (cur == cur_recording)
recordings = recordings->Next;
else {
while (cur->Next != cur_recording)
cur = cur->Next;
/* cur now points to previous list entry */
cur->Next = cur_recording->Next;
}
free(cur_recording->AudioData);
free(cur_recording);
} // end handle_delete
Embedded Systems 40
Allocation Data Structures
Keep free memory in FreeList Size = 412
Next
sorted list of free blocks
typedef struct hdr {
struct hdr * next;
unsigned int size;
Used
}; Size = 508
Next
hdr * FreeList;
Embedded Systems 41
Allocation Operations
To allocate memory
– find first block of size >= requested_size
– modify list to indicate space isn’t free
• if sizes match exactly, remove free block from list
• else split memory
– reduce size field by requested_size, keeping first part of block in free
space
– allocate memory in second part of block
• return pointer to newly allocated block
To free memory depends on block’s memory location
– If before first free block, prepend it at head of free list
– If between free list entries, insert in list
– If after last free block, append it at tail of free list
Freed memory block may be adjacent to other free blocks. If so,
merge contiguous blocks
Embedded Systems 42
Dangers of Dynamic Memory Allocation
Memory leaks waste memory
– Never freeing blocks which are no longer needed. User’s
responsibility.
May accidentally use freed memory
– User’s responsibility.
Allocation speed varies
– Linked list must be searched for a block which is large enough
– Bad for a real-time system, as worst case may be large.
Fragmentation
– Over time free memory is likely to be broken into smaller and
smaller fragments.
– Eventually there won’t be a block large enough for an allocation
request, even though there is enough total memory free
Embedded Systems 43
Heap and Fragmentation
Problem:
– malloc/calloc/free use a heap of memory; essentially a list of blocks
of empty and used memory
– Repeated allocation/free cycles with differently sized allocation
units leads to fragmentation
• Although there may be enough memory free, it may be
fragmented into pieces too small to meet request
Solutions (none optimal):
– Always allocate a fixed size memory element
– Use multiple heaps, each with a fixed element size
Embedded Systems 44
What is an Algorithm?
A formula? A solution? A sequence of steps? A recipe?
A former Vice-President? (Al-Gore-ithm?)
Embedded Systems 45
Pseudo Code
Pseudo code is written in English to describe the functionality
of a particular software module (subroutine)
Include name of module/subroutine, author, date, description
of functionality of module, and actual steps
Often you can take the pseudo code and use them lines in
your program as comments!
Avoid a very fine level of detail (although this may sometimes
be difficult to do)
Avoid writing code – use English, not assembly language (or
higher-level language) instructions
Embedded Systems 46
An Example
Problem: Compare two numbers in x and y, put the larger
number in z. If Equal, put 0 in z.
Sample input/output:
x y z
5 4
5 -4
-5 4
-5 -4
5 5
Embedded Systems 47
Algorithm - Larger
Algorithm:
; Larger: Jim Conrad, 2011-09-13
; Purpose: Compare two numbers in x and
; y, put the larger number in z. If
; equal, put 0 in z.
Perform x-y
If result is positive ; x is bigger
Put x in z, exit
If result is negative ; y is bigger
Put y in z, exit
If zero,
Put 0 in z, exit
Embedded Systems 48
An example
What do you think this does?
Embedded Systems 49