Sunteți pe pagina 1din 49

A “Crash Course” To (Matlab And) C

Programming For TTT4225


Mikko Vehkaperä, mikko@iet.ntnu.no

CREDITS
The C-programming part is heavily derived from:

Lewis Girod
CENS Systems Lab
http://lecs.cs.ucla.edu/~girod/talks/c-tutorial.ppt

1
2
Tentative Time Schedule

Basic Matlab programming Wed 11.2.


What is C? Compiling and running programs, Wed 11.2.
syntax, header files and libraries, functions in C,
some notes on memory, variables
Scopes, mathematical operations, assignment, more Thu 12.2.
on memory and recursive functions, loops, pointers
Arrays, structures, types, dynamic memory allocation, Wed 18.2.
bit-wise operations, makefile, task related issue.

•  The pace is really up to you – if you want, we can also move


faster and cover the topics in two lectures (4 hours).
−  Last year we had only 4 hours for the ”crash course” and the
majority opinion was that the pace was too fast.

3
Some Notes on the “Crash Course”

•  The good and the bad of C and this ”course”:


•  Good: Writing small programs is not that difficult.
•  Bad: Writing good and efficient code is in general difficult.
•  Good: C is a simple language – basics can be covered fast.
•  Bad: You have to do a lot ”from scratch”.
•  Good: These lectures cover (hopefully) everything you need
to know about programming in C for this course.
•  Bad: Programming cannot be learned from lectures.

•  A lot depends on your own effort to learn by trial-and-error.


•  Tutorial (several formats): http://www.crasseux.com/books/
•  The Book for C is “The C Programming Language” by
Kernighan and Richie. They probably have it in library.

4
Matlab?

•  For a good introduction to basic Matlab commands, download


http://www.maths.dundee.ac.uk/~ftp/na-reports/MatlabNotes.pdf
•  In contrast to, e.g., C programming, in Matlab the programmer is
freed from several ”non-productive” tasks, such as:
−  memory management, declaring variables and functions,
data types, problems in passing arrays to functions, …
•  The syntax is very simple, debugging is easy, lots of ready-to-
use functions related to data manipulation and presentation, …
•  Matlab is an interpreted language, hence no need for compiling
•  … which makes it also quite inefficient, especially with programs
using branching (loops, conditional statements, …)
−  Need for interpretor and lack of efficiency makes Matlab
unsuitable for hardware such as DSPs.

5
Functions in Matlab

A function in Matlab is a file ending with “.m” and


starting with the reserved word function. Functions
can take variables as arguments, perform operations .^ ?
to them and return desired variables - just like in C.

The variables (can


be several) that are “geom()” is the name of the function.
returned. The function has to be saved as geom.m!

function ssum = geom(a,N)


% Calculates a geometric series The arguments of
% ssum = a^0 + a^1 + … + a^N the function.
n=0:N;
% Note the vectorized operations Comments in Matlab start with %
ssum= sum(a.^n)

6
Matlab Help - aka. The Scientist’s Best Friend

For every built-in function, typing in Matlab-shell


>> help name_of_the_function
gives you a short description of the function in question.

>> help downsample


DOWNSAMPLE Downsample input signal.
DOWNSAMPLE(X,N) downsamples input signal X by keeping every
N-th sample starting with the first. If X is a matrix, the
downsampling is done along the columns of X.

DOWNSAMPLE(X,N,PHASE) specifies an optional sample offset.


PHASE must be an integer in the range [0, N-1].

For a hypertext help, type:


>> doc name_of_the_function

See the aforementioned Matlab introduction for more information on


basic Matlab programming.

7
Structures in Matlab

struct: Very close to the ‘struct’ data type in C; also reminds an object of
the OO programming languages, but cannot contain methods. A structure
consists of fields that can contain any kind of data. A structure can be
passed to a function as an argument, but be careful with the field names.

>>opt=struct('gamma',0.9,'nbits',4)
opt =

gamma: 0.9000
nbits: 4

>> opt.gamma Fields are accessed by using ‘.’ notation.


ans =

0.9000

>> opt.alpha=0.9 New fields can be easily added.


opt =

gamma: 0.9000
nbits: 4
Struct is a good data type to collect related
alpha: 0.9000 variables together in one place.

8
Some Matlab Functions That May Come in Handy

•  wavrecord: Record sound in Matlab.


•  wavread: Read a ”.wav”-file as a vector in Matlab.
•  wavwrite: Write a Matlab-vector as a ”.wav”-file.
•  soundsc: Autoscale to maximum volume without clipping and play
a vector as sound in Matlab.
•  randn: Generates pseudo random variables drawn from the
standard normal distribution. Can be used, e.g., to simulate
additive white Gaussian noise.
•  filter: One-dimensional digital filter.
•  Upsample / downsample: Up / downsample input signal.
•  decimate / interp: (low-pass anti-aliasing) filter + downsample /
upsample + (low-pass interpolation) filter.

9
Final Notes on Matlab

•  We assume that you are quite familiar with Matlab programming.


•  Start implementing your task as soon as possible in Matlab.
–  Make sure your code works in Matlab before moving to C.
•  It is highly recommended to implement your algorithm also in
“C-style”, i.e., without using Matlab’s special functions before C.
–  Remember, however, that Matlab is very bad with loops. Thus, it is
recommended to implement only the “batch”-version of the
algorithm in Matlab (mainly concerns the audio mixer -task).
•  When you know your algorithm works, generate some reference
data (ber, soundfiles, …) that you can use to check your C code.

10
C Compiler

•  Unlike in Matlab, in C the source code has to processed by a compiler


to transform the high-level programming language into machine
language code that can be directly run by the CPU (as directed by OS).
•  There are several commercial and non-commercial compilers available.
–  You may use any of those. However, we cannot guarantee that the
code you are given works on other compilers than gcc.
–  Do not use any proprietary extensions of C/C++ that some
commercial compilers provide. You’ll be in trouble with hardware.

Recommended: gcc (GNU Compiler Collection)


•  *nixes: You probably have it already installed. Try info gcc or man gcc.
•  Windows: You need to install Cygwin and gcc in it. Not as hard as may sound.
•  Step-by-step instructions for installing Cygwin and gcc:
http://www2.warwick.ac.uk/fac/sci/moac/currentstudents/peter_cock/cygwin/

11
A Quick Digression About the Compiler

#include <stdio.h>

Compilation occurs in two steps:


/* The simplest C Program */
int main(int argc, char **argv)
Preprocess
“Preprocessing” and “Compiling”
{
printf(“Hello World\n”);
return 0;
}

__extension__ typedef unsigned long long int __dev_t; In Preprocessing, source code is “expanded” into
__extension__ typedef
__extension__ typedef
unsigned int
unsigned int
__uid_t;
__gid_t; a larger form that is simpler for the compiler to
__extension__ typedef
__extension__ typedef
unsigned long int
unsigned long long int
__ino_t;
__ino64_t;
understand. Any line that starts with ‘#’ is a line
__extension__ typedef
__extension__ typedef
unsigned int
long int
__nlink_t;
__off_t; that is interpreted by the Preprocessor.
__extension__ typedef long long int __off64_t;
extern void flockfile (FILE *__stream) ;
extern int ftrylockfile (FILE *__stream)
extern void funlockfile (FILE *__stream)
;
; • Include files are “pasted in” (#include)
int main(int argc, char **argv)
{ • Macros are “expanded” (#define)
printf(“Hello World\n”);
return 0;
• Comments are stripped out ( /* */ )
}
• Continued lines are joined ( \ )
\?

my_program The compiler then converts the resulting text into


Compile
binary code the CPU can run directly (via OS).

12
Writing and Running Programs

#include <stdio.h>
/* The simplest C Program */
int main(int argc, char **argv)
{
1. Write text of program (source code) using an editor
printf(“Hello World\n”);
return 0;
such as emacs / vim, save as file e.g. my_program.c
}

2. Run the compiler to convert program from source to


an “executable” or “binary”:
$ gcc –Wall –g my_program.c –o my_program

$ gcc -Wall –g my_program.c –o my_program


tt.c: In function `main':
-Wall –g ?
tt.c:6: parse error before `x'
tt.c:5: parm types given both in parmlist and separately
tt.c:8: `x' undeclared (first use in this function)
tt.c:8: (Each undeclared identifier is reported only once
3-N. Compiler gives errors and warnings; edit source
tt.c:8: for each function it appears in.)
tt.c:10: warning: control reaches end of non-void function
file, fix it, and re-compile
tt.c: At top level:
tt.c:11: parse error before `return'

N. Run it and see if it works 


./?
$ ./my_program
my_program Hello World
$ ▌

13
C Syntax and Hello World

#include inserts another file. “.h” files are called


“header” files. They contain stuff needed to interface to
libraries and code in other “.c” files. Can your program have
What do the < > more than one .c file?
mean? See next page.
This is a comment. The compiler ignores this.

#include <stdio.h>
The main() function is
/* The simplest C Program */ always where your program
int main(int argc, char **argv) starts running.
{
Blocks of code (“lexical
printf(“Hello World\n”); scopes”) are marked by { … }
return 0;
}

Return ‘0’ from this function Print out a message. ‘\n’ means “new line”.

14
Standard Header Files and Libraries

$ cat /usr/src/include/stdio.h
[lots of code precedes]
int fprintf(FILE * __restrict, const char * __restrict, ...);
[lots of code follows]

Header files of type <hrdfile.h> declare


variables and functions provided by the
#include <stdio.h>
standard libraries. Here the prototype of
/* The simplest C Program */ function fprintf was defined.
int main(int argc, char **argv)
{
printf(“Hello World\n”); In addition to declarations in the header
return 0; files, your code needs to be linked against
the libraries that provide the actual
} implementations of these functions (e.g,
Can you define and include
your custom header files? glibc.so in Linux for this case).
See next page.

15
Custom Header Files?

#ifndef __TALKTHROUGH_H__
To avoid declaring same functions #define __TALKTHROUGH_H__
or variables multiple times. Use in
multi-file programs. #include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include "talkthrough.h”
#define HDRDATATYPE int8_t
[... code …] #define INPUTDATATYPE int16_t
#define OUTPUTDATATYPE int16_t
int main(int argc, char **argv){ #define HDRLEN 44

[... code …] /* Function prototypes */


void Process_Data(INPUTDATATYPE *,
} OUTPUTDATATYPE *, size_t);

talkthrough.c #endif
talkthrough.h
Why custom header files?

16
OK, We’re Back.. What is a Function?

A Function is a series of instructions to run. You pass


Arguments to a function and it returns a Value.

main() is a Function. It’s only special because it


always gets called first when you run your program.

Return type, or void Comment /* TEXT */, can be multiple lines.

#include <stdio.h>
Function Arguments
/* The simplest C Program */
int main(int argc, char **argv)
Calling a Function: printf() is just
{
another function, like main(). It’s defined
printf(“Hello World\n”); for you in a “library”, a collection of
return 0; functions you can call from your program.
}
Returning a value (0 == EXIT_SUCCESS in <stdlib.h>)

17
What is “Memory”?

Memory is like a big table of numbered Addr Value


slots where bytes can be stored. 0
1
The number of a slot is its Address. 2
One byte Value can be stored in each slot. 3
72?
4 ‘H’ (72)
man ascii
Some “logical” data values span more than
5 ‘e’ (101)
one slot, like the character string “Hello\n”
6 ‘l’ (108)
A Type names a logical meaning to a span 7 ‘l’ (108)
of memory. Some simple types are: 8 ‘o’ (111)
char a single character (1 slot) #include <inttypes.h> 9 ‘\n’ (10)
char [10] an array of 10 characters int32_t, int16_t, int8_t
10 ‘\0’ (0)
int signed 4 byte integer
float 4 byte floating point not always… 11
int64_t signed 8 byte integer Signed?… 12

18
What is a Variable?
symbol table? -g

A Variable names a place in memory where Symbol Addr Value


you store a Value of a certain Type. 0
1
You first Define a variable by giving it a 2
name and specifying the type, and
3
optionally an initial value declare vs define?
x 4 ?

Initial value of x is undefined y 5 ‘e’ (101)


char x;
char y=‘e’; 6
7
The compiler puts them
Initial value 8
somewhere in memory.
9
Name What names are legal?
10
Type is single character (char) 11
extern? static? const? 12

19
Multi-byte Variables

Different types consume different amounts Symbol Addr Value


of memory. Most architectures store data 0
on “word boundaries”, or even multiples of 1
the size of a primitive data type (int, char)
2
3
char x;
char y=‘e’; x 4 ?
int z = 0x01020304; y 5 ‘e’ (101)
6
0x means the constant is padding
written in hex 7
z 8 4
9 3
An int consumes 4 bytes
10 2
11 1
12

20
Talkthrough.tar.gz

Compiling using gnu make.


abyss% ls
Makefile example.sh raw2wav.c talkthrough.h
Doc input.wav refman.pdf tools.c
doxygen.cfg process_data.c talkthrough.c wav_header.bin
abyss% make
make: Target compiled.
abyss% sh example.sh You can use this file as a template for your
own algorithms.

Reads input.wav, writes outputs.wav. Check inside for an example


how to use these programs. For usage information, type:

abyss% ./talkthrough –h
abyss% ./raw2wav -h

21
Scopes, mathematical operations, assignment, more Thu 12.2.
on memory and recursive functions, loops, pointers

22
Lexical Scoping (Returns nothing)

void p(char x)
Every Variable is Defined within some scope. {
A Variable cannot be referenced by name char y;
/* p,x */

(a.k.a. Symbol) from outside of that scope. /* p,x,y */


char z;
/* p,x,y,z */
}
Lexical scopes are defined with curly braces { }. /* p */
char z;
/* p,z */
The scope of Function Arguments is the
void q(char a)
complete body of the function. {
char b;
/* p,z,q,a,b */
The scope of Variables defined inside a
{
function starts at the definition and ends at char c;
the closing brace of the containing block }
/* p,z,q,a,b,c */

legal?
char d;
The scope of Variables defined outside a /* p,z,q,a,b,d (not c) */
function starts at the definition and ends at }

the end of the file. Called “Global” Vars. /* p,z,q */

23
Comparison and Mathematical Operators

Be bery careful with the


== equal to operators highlighted in red!
The rules of precedence are clearly
< less than defined but often difficult to remember
<= less than or equal
> greater than or non-intuitive. When in doubt, add
>= greater than or equal parentheses to make it explicit. For
!= not equal
&& logical and
oft-confused cases, the compiler will
|| logical or give you a warning “Suggest parens
! logical not around …” – do it!
+ plus & bitwise and
-  minus | bitwise or Beware division:
More
* mult ^ bitwise xor
details
• If second argument is integer, the
/ divide ~ bitwise not
% modulo << shift left later. result will be integer (rounded):
>> shift right 5 / 10  0 whereas 5 / 10.0  0.5
• Division by 0 will cause a FPE

In C, 0 means “false”, and any Don’t confuse & and &&..


other value means “true”. 1 & 2  0 whereas 1 && 2  <true>

24
Assignment Operators

x = y assign y to x x += y assign (x+y) to x


x++ post-increment x x -= y assign (x-y) to x
++x pre-increment x x *= y assign (x*y) to x
x-- post-decrement x x /= y assign (x/y) to x
--x pre-decrement x x %= y assign (x%y) to x

Note the difference between ++x and x++:

int x=5; int x=5;


int y; int y;
y = ++x; y = x++;
/* x == 6, y == 6 */ /* x == 6, y == 5 */

Don’t confuse = and == The compiler will warn “suggest parens”.

int x=5; int x=5;


if (x==6) /* false */ if (x=6) /* always true */
{ {
/* ... */ /* x is now 6 */
} }
/* x is still 5 */ /* ... */

25
if Statement and Recursive Function

#include <stdio.h>
/* if evaluated expression is not 0 */ #include <inttypes.h>
if (expression) {
/* then execute this block */ float pow(float x, uint32_t exp)
} {
else { /* base case */
/* otherwise execute this block */ X?Y:Z if (exp == 0) {
} return 1.0;
}

/* “recursive” case */
Remember the parenthesis and the return x*pow(x, exp – 1);
curly braces. }

int main(int argc, char **argv)


{
/* Matlab version. */ float p;
if expression p = pow(2.0, 3);
/* then execute this block */ printf(“p = %f\n”, p);
else return 0;
/* otherwise execute this block */ }
end
What’s the output?

26
Note On The “Stack” And Recursive Functions

#include <stdio.h>
Each function call allocates a “stack frame” #include <inttypes.h>
where variables within that function’s scope float pow(float x, uint32_t exp)
will reside. {
/* base case */
if (exp == 0) {
return 1.0;
Problem: “recursion” eats stack space (in C). }
Each loop must allocate space for arguments
/* “recursive” case */
and local variables, because each new call return x*pow(x, exp – 1);
}
creates a new “scope”.
int main(int argc, char **argv)
{
float x 5.0 float p;
uint32_t exp 0 Return 1.0 p = pow(5.0, 1);
printf(“p = %f\n”, p);
float x 5.0 return 0;
}
uint32_t exp 1 Return 5.0

int argc 1
while (condition) {
char **argv 0x2342 statements;

float p undefined
5.0
Grows }

27
The “for” Loop

The “for” loop is just shorthand for this “while” loop structure.

float pow(float x, uint exp) float pow(float x, uint exp)


{ {
float result=1.0; float result=1.0;
int i; int i;
i=0; for (i=0; (i < exp); i++) {
while (i < exp) { result = result * x;
result = result * x; }
i++; return result;
} }
return result;
} int main(int argc, char **argv)
{
int main(int argc, char **argv) float p;
{ p = pow(10.0, 5);
float p; printf(“p = %f\n”, p);
p = pow(10.0, 5); return 0;
printf(“p = %f\n”, p); }
return 0;
}

28
Can a Function Modify Its Arguments?

What if we wanted to implement a function pow_assign()


that modified its argument, so that these are equivalent:
float p = 2.0; float p = 2.0;
/* p is 2.0 here */ /* p is 2.0 here */
p = pow(p, 5); pow_assign(p, 5);
/* p is 32.0 here */ /* p is 32.0 here */

Would this work?

void pow_assign(float x, uint exp)


{
float result=1.0;
int i;
for (i=0; (i < exp); i++) {
result = result * x;
}
x = result;
}

29
NO!

Remember the stack!

void pow_assign(float x, uint exp)


{
float result=1.0; In C, all arguments are
int i;
for (i=0; (i < exp); i++) {
passed as Values
result = result * x;
}
x = result;
} But, what if the argument is
int main(int argc, char **argv)
{
the address of a variable?
float p=2.0;
pow_assign(p, 5);
}

float x 2.0
32.0
uint32_t exp 5
float result 1.0
32.0

float p 2.0 Grows

30
Passing Addresses – Pseudo Code

Symbol Addr Value


Recall our model for variables stored 0
in memory
1
2
What if we had a way to find out the
address of a symbol, and reference 3
that memory location by address? char x 4 ‘H’ (72)
char y = 101; char y 5 ‘e’ (101)
/* Initial values 6
address_of(y) == 5
memory_at[5] == 101 (‘e’) */ 7

void f(address_of_char p)
8
{
/* Modify the content of memory */
9
memory_at[p] = memory_at[p] - 32;
}
10
f(address_of(y)); /* i.e. f(5) */ 11
/* y is now 101-32 == 69 */
12

31
“Pointers”

This is exactly how “pointers” work.


A “pointer type”: pointer to char
“address of” or reference operator: &
“memory_at” or dereference operator: *

void f(address_of_char p) void f(char * p)


{ {
memory_at[p] = memory_at[p] - 32; *p = *p - 32;
} }

char y = 101; /* y is 101 */ char y = 101; /* y is 101 */


f(address_of(y)); /* i.e. f(5) */ f(&y); /* i.e. f(5) */
/* y is now 101-32 = 69 */ /* y is now 101-32 = 69 */

Pointers are used in C for many other purposes:


• Passing large objects without copying them
• Accessing dynamically allocated memory
• Referring to functions

32
Pointer Validity

A Valid pointer is one that points to memory that your program controls.
Using invalid pointers will cause non-deterministic behavior, and will
often cause Linux to kill your process (SEGV or Segmentation Fault).

There are two general causes for these errors: Always initialize pointers to NULL!
• Program errors that set the pointer value to a strange number
• Use of a pointer that was at one time valid, but later became invalid

Will ptr be valid or invalid?

char * get_pointer()
{
char x=0;
return &x;
}

{
char * ptr = get_pointer();
*ptr = 12; /* valid? */
}

33
Answer: Invalid!

A pointer to a variable allocated on the stack becomes invalid when


that variable goes out of scope and the stack frame is “popped”. The
pointer will point to an area of the memory that may later get reused
and rewritten.

char * get_pointer()
{
char x=0;
return &x;
} But now, ptr points to a
{
location that’s no longer in
char * ptr = get_pointer(); use, and will be reused the
*ptr = 12; /* valid? */
other_function(); next time a function is called!
}

101 charaverage
int x Return
0 101
12
456603

100 char * ptr 101


? Grows

34
Arrays, structures, types, dynamic memory allocation, Wed 18.2.
bit-wise operations, makefile, task related issue.

35
Arrays in Matlab and C

•  Let x be a one dimensional array with N elements.


•  Let y be a two dimensional array with NxM elements.

Matlab C

•  Elements of x: •  Elements of x:
x(1), x(2),…, x(N) x[0], x[1],…, x[N-1]
•  Elements of y: •  Elements of y:
y(1,1),…, y(N,M) y[0][0],…, y[N-1][M-1]
•  Arrays can be passed as •  Arrays are passed to
arguments in funtions. functions via their address.
•  Commands like: •  Copying of arrays via loops,
z = y(:,1); z = zeros(3); memcpy, etc. Initialization:
are possible. double z[3]={42,666,69};
double z[3];
Arrays are not automatically
initialized, e.g., to zero

36
Arrays in C

Arrays in C are composed of a particular type, laid out in memory in a


repeating pattern. Array elements are accessed by stepping forward in
memory from the base of the array by a multiple of the element size.

/* define an array of 10 chars */


char x[5] = {‘t’,’e’,’s’,’t’,’\0’};
Strings in C are NULL-terminated
(‘\0’)

character
arrays
(include
<string.h>).
/* accessing element 0 */
x[0] = ‘T’;
Arrays in C are 0-indexed (here, 0..9)
/* pointer arithmetic to get elt 3 */
char elt3 = *(x+3); /* x[3] */ x[3] == *(x+3) == ‘t’ (NOT ‘s’!)
/* x[0] evaluates to the first element;
* x evaluates to the address of the
* first element, or &(x[0]) */
Symbol Addr Value
char x [0] 100 ‘t’
/* 0-indexed for loop idiom */
#define COUNT 10 char x [1] 101 ‘e’
char y[COUNT]; For loop that iterates
int i;
char x [2] 102 ‘s’
for (i=0; i<COUNT; i++) { from 0 to COUNT-1. char x [3] 103 ‘t’
/* process y[i] */ Memorize it!
printf(“%c\n”, y[i]); char x [4] 104 ‘\0’
}

37
Arrays and Pointers

Arrays and pointers are very much related. Especially, when you pass
an array to a function as an argument, it is interpreted as passing the
memory address of the first element in the array.

Static memory allocation.

talkthrough.c
int x[100];
int *y = NULL;
y = (int *) malloc((ysize)*sizeof(int));
Dynamic memory
allocation. More later.
Process_Data(x, y, 100);
Process_Data(&x[0], &y[0], 100);

void Process_Data(int *x, int *y, int nread) Note that you can use the
{
unsigned int i; pointers as arrays here.
for (i = 0; i < nread; i++)
y[i] = x[i];
Another option would be:
} *(y+i) = *(x+i);
process_data.c

38
How to Parse and Define C Types

At this point we have seen a few basic types, arrays and pointer types.
So far we’ve glossed over how types are named.

int x; /* int; */ typedef int T;


int *x; /* pointer to int; */ typedef int *T;
typedef defines
int x[10]; /* array of ints; */ typedef int T[10];
a new type
int *x[10]; /* array of pointers to int; */ typedef int *T[10];
int (*x)[10]; /* pointer to array of ints; */ typedef int (*T)[10];

C type names are parsed by starting at the type name and working
outwards according to the rules of precedence:

x is
an array of
pointers to
int *x[10]; int
Arrays are the primary
source of confusion. When
x is in doubt, use extra parens to
int (*x)[10]; clarify the expression.
a pointer to
an array of
int

39
Structures

struct: a way to compose existing types into a structure

#include <sys/time.h> struct timeval is defined in this header


/* declare the struct */
struct my_struct { structs define a layout of typed fields
int counter;
float average;
struct timeval timestamp;
structs can contain other structs
uint in_use:1;
uint8_t data[0]; fields can specify specific bit widths
}; Why?

/* define an instance of my_struct */ A newly-defined structure is initialized


struct my_struct x = {
in_use: 1, using this syntax. All unset fields are 0.
timestamp: {
tv_sec: 200
}
};
x.counter = 1; Fields are accessed using ‘.’ notation.
x.average = sum / (float)(x.counter);

struct my_struct * ptr = &x; A pointer to a struct. Fields are accessed


ptr->counter = 2;
(*ptr).counter = 3; /* equiv. */
using ‘->’ notation, or (*ptr).counter

40
Dynamic Memory Allocation

So far all of our examples have allocated variables statically by


defining them in our program. This allocates them in the stack.

What if we want to allocate variables based on user input or $ man calloc


$ man memset
at run-time? This requires dynamic allocation.

sizeof() reports the size of a type in bytes


int * alloc_ints(size_t requested_count)
{ calloc() allocates memory
int * big_array;
big_array = (int *)calloc(requested_count, sizeof(int));
for N elements of size k
if (big_array == NULL) {
printf(“can’t allocate %d ints: %m\n”, requested_count); Returns NULL if can’t alloc
return NULL;
} %m  printf(“%s”, strerr(errno))

/* now big_array[0] .. big_array[requested_count-1] are It’s OK to return this pointer.


* valid and zeroed. */
return big_array; It will remain valid until it is
} freed with free()

41
Caveats with Dynamic Memory

Dynamic memory is useful. But it has several caveats:

Whereas the stack is automatically reclaimed, dynamic allocations must be


tracked and free()’d when they are no longer needed. With every
allocation, be sure to plan how that memory will get freed. Losing track of
memory is called a “memory leak”.

Whereas the compiler enforces that reclaimed stack space can no longer
be reached, it is easy to accidentally keep a pointer to dynamic memory
that has been freed. Whenever you free memory you must be certain that
you will not try to use it again. It is safest to erase any pointers to it.

Because dynamic memory always uses pointers, there is generally no way


for the compiler to statically verify usage of dynamic memory. This means
that errors that are detectable with static allocation are not with dynamic

42
Some Common Errors and Hints

sizeof() can take a variable reference in place of a type name. This gurantees the right
allocation, but don’t accidentally allocate the sizeof() the pointer instead of the object!

/* allocating a struct with malloc() */ malloc(size_t n) allocates n bytes


struct my_struct *s = NULL;
s = (struct my_struct *)malloc(sizeof(*s)); /* NOT sizeof(s)!! */
if (s == NULL) {
printf(stderr, “no memory!”); Always check for NULL.. Even if you just exit(1).
exit(1);
}
malloc() does not zero the memory,
memset(s, 0, sizeof(*s)); so you should memset() it to 0.
/* another way to initialize an alloc’d structure: */
struct my_struct init = {
counter: 1,
average: 2.5,
in_use: 1
};

/* memmove(dst, src, size) (note, arg order like assignment) */


memmove(s, &init, sizeof(init));
memmove is preferred because it is
/* when you are done with it, free it! */ safe for shifting buffers
free(s); Why?
s = NULL;
Use pointers as implied in-use flags!

43
Reading and Writing Files in C

Before a file can be accessed, it has to be opened with fopen. fopen


returns a pointer to a data type FILE (or a NULL-pointer in error).

[… code …]

if ((ifp = fopen(file, "rb")) == NULL) {


fprintf(stderr, "\nCannot open file %s",filename);
exit(EXIT_FAILURE);
}
”rb” will open a binary file for reading,
% Check the length of the file ”wb” opens a file for writing.
fseek(ifp, 0, SEEK_END);
buffer_len = ftell(ifp);
rewind (ifp); Function fread takes two pointers, data
while ((nread=fread(x, sizeof(INPUTDATATYPE),
type and number of data chuncks as its
buffer_len, ifp))){ arguments.
Process_Data(x, y, nread);
fwrite(y, nread, sizeof(OUTPUTDATATYPE), ofp);
}

[… code …]
fclose is the counterpart of fopen, i.e., it
closes the file and deletes the pointer.

44
Macros

Macros can be a useful way to customize your interface to C and


make your code easier to read and less redundant. However, when
possible, use a static inline function instead.

Macros and static inline functions must be included in any file that
uses them, usually via a header file. Common uses for macros:

/* Macros are used to define constants */


#define FUDGE_FACTOR 45.6 Float constants must have a decimal
#define MSEC_PER_SEC 1000 point, else they are type int
#define INPUT_FILENAME “my_input_file”
enums
/* Macros are used to do constant arithmetic */
Why?
#define TIMER_VAL (2*MSEC_PER_SEC) Put expressions in parens.
/* Macros are used to capture information from the compiler */
#define DBG(args...) \
do { \ Multi-line macros need \
fprintf(stderr, “%s:%s:%d: “, \
__FUNCTION__, __FILE__, __LINENO__); \ args… grabs rest of args
fprintf(stderr, args...); \
} while (0) Why?
Enclose multi-statement macros in do{}while(0)
/* ex. DBG(“error: %d”, errno); */

45
Some Task Specific Notes

In your assignments you need some bitwise operations and fmod


function to create a “cyclic buffer” for the real-time C program.
$ man fmod

main() main()
{ {
unsigned int a = 60; /* 60 = 0011 1100 */ /* 4 = 0000 0100 */
unsigned int b = 13; /* 13 = 0000 1101 */ unsigned int Value=4;
unsigned int c = 0; unsigned int Shift=2;

/* Bitwise AND */ /* 16 = 0001 0000 */


c = a & b; /* 12 = 0000 1100 */ Value = Value << Shift;

/* Bitwise OR */ /* 64 = 0100 0000 */


c = a | b; /* 61 = 0011 1101 */ Value <<= Shift;

/* Bitwise XOR */ /* Prints 64 */


c = a ^ b; /* 49 = 0011 0001 */ printf("%d\n", Value);
} }

The “cyclic buffer” allows you to save memory in the real-time enviroment
by overwriting the already used data. Especially useful for the up/
downsampling part.

46
Simple Makefile
Assume
we
have
files:
hellomake.c,
hellofunc.c
and
hellofunc.h
in
our
project.


#include “hellofunc.h"

int main() { Program calls a function from hellofunc.c.


/* Call a function from other file */ This system can be compiled as:
myPrintHelloMake(); $ gcc hellomake.c hellofunc.c –o hellomake

return(0);
}

A makefile contains the “rules” how the system has to be compliled. A program
called make reads the Makefile (default name), parses it and calls the
compiler / linker appropriately. Here’s a simple makefile for the above system:
$ info make
hellomake: hellomake.c hellofunc.c
gcc hellomake.c hellofunc.c –o hellomake –I.

The
first
line
contains
all
files
the
program
is
depends
on.
This
is
used
by

make
to
decide
which
files
have
changed
and
need
to
be
re-compiled.
NOTE:

The
lines
not
having
target:
have
to
start
with
’tab’-character.


47
More Sophisticated Makefile

CFLAGS = -O2 -Wall -I.


CC = gcc Track also changes in the header-file.
DEPS = talkthrough.h

TALKTHROUGH_TRG = talkthrough
TRGS = $(TALKTHROUGH_TRG) Compiler, flags and files as macros. If
you add / remove files from your project
OTHER_OBJS_TT = process_data.o tools.o you need to change these macros.
OBJS = $(TALKTHROUGH_TRG).o $(OTHER_OBJS_TT)

SRCS = $(TALKTHROUGH_TRG).c process_data.c tools.c

all: $(TALKTHROUGH_TRG) Automatic variable $< is the name of


@echo 'make: Target compiled.' the of the first prerequisite (.c files).
$(TALKTHROUGH_TRG): $(OBJS_TT) $(DEPS) Tells the compiler that object files
@$(CC) $(CFLAGS) -o $@ $(OBJS_TT)
(.o) depend on .c and .h files and
.c.o: intructs $(CC) to compile but not
@${CC} ${CFLAGS} ${INCLUDES} -c $< link (the flag –c).

48
The Wave Format

http://ccrma.stanford.edu/courses/422/projects/WaveFormat/

000358_JF.wav
[4] ChunkID = 52 49 46 46 ("RIFF")
[4] ChunkSize = 24 d5 02 00 = 0x0002d524 (185636)
[4] Format = 57 41 56 45 ("WAVE")

[4] Subchunk1ID = 66 6d 74 20 ("fmt")


[4] Subchunk1Size = 10 00 00 00 = 0x00001000 (PCM = 16)
[2] AudioFormat = 01 00 = 0x0001 (PCM = 1)
[2] NumChannels = 01 00 = 0x0001 (mono = 1)
[4] SampleRate = 80 3e 00 00 = 0x00003e80 (16000)
[4] ByteRate = 00 7d 00 00 = 0x00007d00 (32000)
[2] BlockAlign = 02 00 = 0x0002 (2)
[2] BitsPerSample = 10 00 = 0x0010 (16)

[4] Subchunk2ID = 64 61 74 61 ("data")


[4] Subchunk2Size = 00 d5 02 00 = 0x0002d500 (185600)

04 00 03 00 04 00 fe ff ...

0x0004 0x0003 0x00004 0xfffe ... $ man hexdump

49

S-ar putea să vă placă și