Вы находитесь на странице: 1из 40

C and Data Structures in Pintos

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark Wheelhouse


Imperial College London

January 2016

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

1 / 40

Introduction

Aims of this lecture:


Review some C from last years course
Emphasize specific C constructs helpful for Pintos

Table of contents:
Basic preprocessor use
Pointer recap
Linked lists in Pintos
Misc.

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

2 / 40

The C Preprocessor

The preprocessing is the first stage in the compilation of any C


program.
It carries out the tokenization and comment removal.
In general, directives starting with # are preprocessor instructions.
Including the obvious #include

You can call it with gcc -E

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

3 / 40

#define

What?
#define identifier replacement
Example: #define PI 3.0
Subsequent occurences of identifier will be replaced by
replacement

Usage
Use #define to replace small amounts of code to make it more
readable or avoid magic numbers
Use it to define constants at compile time:
#define DEBUG 1

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

4 / 40

Macros

What?
#define can also be used with parameters.
#define identifier( params ) replacement
Example: #define P(X) printf(%d,(X))
Subsequent occurences of identifier will be replaced by
replacement, with params substituted in.

Usage
Use #define to replace small amounts of code to make it more
readable or define simple functionality
Macros have less execution overhead than a function call

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

5 / 40

Macro Safety
Some general points to be aware of when using macros in C:
You should surround each term of a macro with parentheses:
#define TWICE(x) x * 2
TWICE(3 + 5)
result: 3 + 5 * 2
You should surround the whole macro replacement with parentheses:
#define TWICE(x) (x) * 2
10 / TWICE(5)
result: 10 / (5) * 2
The correct version of this macro is:
#define TWICE(x) ((x) * 2 )

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

6 / 40

Macro Safety contd.

For macros that execute full statements, a dumb do-while loop


helps encapsulation:
#define P(X) do { printf(\%d,(X)); } while (0)
The final semicolon is missing on purpose
Beware: debugging macros can be a nightmare
Keep them simple!
Do not use them as function replacements

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

7 / 40

Macro examples
Return max of two elements
#define MAX(x, y) do { typeof(x) _x = (x); \
typeof(y) _y = (y); \
_x > _y ? _x : _y } while (0)

Swap content of two variables


#define SWAP(x, y) do { typeof(x) swp = x; x = y; \
y = swp; } while (0)

Print trace for debugging


#define debug_print(fmt, ...) \
do { if (DEBUG) fprintf(stderr, "%s:%d:%s(): " fmt, \
__FILE__, __LINE__, __func__, ##__VA_ARGS__); } while (0)

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

8 / 40

Include Guards

This problem appears when multiple files include the same header
my lib.h
struct my_struct {int x;};
my extended lib.h
#include "my_lib.h"
my program.c
#include "my_lib.h"
#include "my_extended_lib.h"

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

9 / 40

Include Guards

Solution: #ifdef & #ifndef


Used to control preprocessing with conditional statements that are
evaluated during preprocessing, allowing selective inclusion of code
#ifndef MY_LIB_H
#define MY_LIB_H

/* If MY_LIB_H isnt defined... */


/* Define the macro MY_LIB_H */

struct my_struct {int x;};


#endif

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

10 / 40

Conditional Compilation
#ifdef and #ifndef are also used for conditional compilation
Example:
struct my_struct {
int x;
#ifdef VERBOSE
char buffer[1000];
#endif
};
Common uses are:
Debug/test/verbose
Platform-dependent code
To address dependency issues
Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark
C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

11 / 40

Defining with gcc

You can also define flags in the terminal.


This:
#define DEBUG 1
Is the same as this:
$ gcc -D DEBUG main.c
Very useful when used in Make or CMake!

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

12 / 40

Pointers

A pointer is a special variable type in C


A pointer contains a memory address you can access through it
Any variable type has a pointer associated to it
You really should know this by now

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

13 / 40

Declaring pointers

To declare a pointer prepend a * to the variables name


double *doublePtr;
int *intPtr;
int *a, b;
int **intPtrPtr;

/*
/*
/*
/*

A
A
A
A

pointer
pointer
pointer
pointer

to
to
to
to

a double */
an int */
int a and an int b */
a pointer to an int */

Pointers can have arbitrary levels of indirection i.e. you can have a
pointer to a pointer.

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

14 / 40

Pointer operators

We mostly use two operators to deal with pointers:


The address operator & takes a value and returns an address. Can
be read in English as address of.
The dereference operator * takes a pointer and returns the value it
points to. Can be read in English as content of.

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

15 / 40

Pointer operators contd.


char c = t;
char *p;
p = &c;

0x2b00b1e5:
0x2b0a43e0:

c = t
p = 0x2b00b1e5

0x2b00b1e5:
0x2b0a43e0:

c = u
p = 0x2b00b1e5

*p = u;

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

16 / 40

Stack and heap

In C we handle two kinds of memory:

The stack
Handled entirely by the CPU
Emptied at the end of current scope
Slightly faster access

The heap
Handled mostly by the programmer
Lives forever (or until freed)
Much bigger space

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

17 / 40

Memory allocation
Stack
float v[10];

Heap
float *v;
v = (float *) malloc(10*sizeof(float));
...
free(v) /* Remember to free the memory! */
Other than that, float v[] and float *v can usually be treated
equivalently.
But it can get messy if mixed agree with your teammates.

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

18 / 40

Pointers and arrays

Theres no array type in C


We use pointers with reserved memory locations
char *s = (char *) malloc(8*sizeof(char));
s

space reserved for s


For any integer n, *(s+n) is equivalent to s[n]

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

19 / 40

Pointer Arithmetic
When adding to pointers, the type of the pointer is important.
struct my_struct {
int a;
int b;
};
struct my_struct s[2];
struct my_struct *sp = &s[0];
int *ip = (int *) sp;
sp++; /* points to the second struct */
ip++; /* points to the second int of the first struct */

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

20 / 40

Pointer tip

Anti-bug tip
Set all your pointers to NULL at initialization!
(And maybe also after freeing them)
That allows you to do things like:
assert( p != NULL );
*p = 1;
if (p) free(p);
That wouldnt necessarily work if p wasnt explicitly set to NULL
beforehand.

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

21 / 40

A word about const

With pointers, you can have constant pointers, pointers to constant


values or both.
int val = 5;
const int *ptr1 = &val;
/* ptr1 can be modified, val cannot */
int *const ptr2 = &val;
/* val can be modified, ptr2 cannot */
const int *const ptr3 = &val; /* neither val nor ptr3 can be modified */

Very powerful resource.


Gets messy very quickly with multiple levels of indirection.
Use const as much as you can!

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

22 / 40

Pointers as arguments
Pass by reference
When you want to modify an argument inside the function, pass a pointer.
void setInt(int *v, int i) { *v = i; }

Passing pointer-const instead of value


Very useful trick!
void foo(int n, const float *X)
Benefits:
Enforce const-ness of input
Avoid potentially expensive useless copies

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

23 / 40

Pointers and debugging


Use a debugger!
Use GDBs x command to print address and content of a variable
In main.c
char *p;
char str[6];
strcpy(str, hello);
p = str;
In GDB:
(gdb) x/5c &str
0x601058 <str>: 104 h 101 e 108 l 108 l 111 o
(gdb) p p
0x601058 <str> hello
(gdb) x &p
0x601050 <p>: 88 X
Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark
C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

24 / 40

Linked lists

Anatomy of a (doubly) linked list:


5

13

21

List element structure


struct list_elem
{
struct list_elem *prev;
struct list_elem *next;
};

/* Previous list element. */


/* Next list element. */

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

25 / 40

Operations on linked lists


Insertion:
5

13

21

8
Deletion:
13
5

21

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

26 / 40

Motivation

Why would anyone ever use lists?


Useful to compare against arrays in terms of:
Get/set methods
v[4] = 42;
list_set(ls, 4, 42);
Insertion/deletion
v = realloc(...); v[5] = 86;
list_insert(&(e1.next), &(e2.next));
Memory usage

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

27 / 40

Implementation of a linked list


List element structure
struct list_elem {
struct list_elem *prev;
struct list_elem *next;
};

/* Previous list element. */


/* Next list element. */

Declaring a struct to be used in a list


struct my_element {
int a;
struct list_elem next; };

The list structure itself


struct list {
struct list_elem head;
struct list_elem tail;
};

/* List head. */
/* List tail. */

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

28 / 40

Lists in Pintos

Its very important that you understand how to use lists in Pintos
The Pintos list implementation in <list.h> contains several useful
functions.
Dont reinvent the wheel use them!

Declaring and initialising a list


struct list my_list;
list_init(&my_list);

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

29 / 40

Lists in Pintos contd.

Inserting an item
/* e_before is the list_elem of the struct that
you want to insert the item after */
list_insert (&(e_before.next) , &(e.next));

Fetching the front element


struct list_elem *ep = list_front (&my_list);

Casting a list elem to its parent struct


struct my_element *my_ep =
list_entry(ep, struct my_element, next);

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

30 / 40

Lists in Pintos contd. II

list.h also contains some useful macros.

Casting a list elem to its parent struct


#define list_entry(LIST_ELEM, STRUCT, MEMBER)
\
((STRUCT *) ((uint8_t *) &(LIST_ELEM)->next
\
- offsetof (STRUCT, MEMBER.next)))
Remember to free the memory you use!
Valgrind can be of help.

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

31 / 40

Function Pointers
Just like you can have a pointer to a variable in C, you can also have a
pointer to a function.

Declare Function Pointer


int (*fp)( int );

Define Functions
int f1( int x ) { return x; }
int f2( int x ) { return x+1; }

Pair Function Pointer to Function


fp = f1;

/* fp = &f1; also accepted */

Execute Function Using Pointers


int r = (*fp)( 5 );
Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark
C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

32 / 40

Function Pointers contd.

Function pointers are everywhere in the standard library


Example: sort array wrt function compar:
void qsort(void *base, size_t nitems, size_t size,
int (*compar)(const void *, const void*))
Theyre also in Pintos:
void list_sort (struct list *, list_less_func *, void *aux);
Function pointers are cool. Learn about them and use them!

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

33 / 40

typedef and function pointers

Declaring function pointers can get cumbersome


Enter typedef
Example from Pintos:
typedef bool list_less_func (const struct list_elem *a,
const struct list_elem *b,
void *aux);
Careful with the naming. Its very easy to lose track and confuse
them with variable pointers

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

34 / 40

Callbacks
Very useful thing you can do with function pointers.
void fill(int *v, int n, int (*getValue)(void)) {
for (int i = 0; i < n; i++) v[i] = getValue();
}
int getRandomValue(void) { return rand(); }
int main(void) {
int myarray[10];
fill(myarray, 10, getRandomValue);
return 0;
}
Watch out with the * and & operators!
Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark
C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

35 / 40

Function pointer arrays


#include <stdio.h>
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);
int (*oper[4])(int a, int b) = {add, sub, mul, div};
int main() {
int i, result;
int a = 10;
int b = 5;
printf("Enter the value between 0 and 3 : ");
scanf("%d", &i);
result = oper[i](a, b);
}
Example from wikibooks.org
Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark
C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

36 / 40

C99 data types

Booleans
stdbool.h defines type bool
true expands to 1
false expands to 0
Examples of use in code same as in any other language, really

The stdbool.h source


#define bool _Bool
#define true 1
#define false 0

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

37 / 40

Coding Standards

Maintaining a consistent coding standard will help you:


Debug large blocks of code
Work with other peoples code
Get more marks (remember were marking the style of your code!)

Finding Style Guidelines


Pintos Section C.1 explains the style guidelines we expect
The GNU standards are worth looking at:
http://www.gnu.org/prep/standards/html_node/index.html

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

38 / 40

Coding Standards cont.

Some general points to keep in mind:


Comment your code.
Common sense goes a long way, if you think something is messy or
over-complicated, it probably is.
Bear in mind the long-standing maxims: KISS, RTFM.
Comment your code!
Please stick to 79 characters per line as usual
No, seriously, comment your code!!!
(However, leaving old code commented-out in your source files will
only be confusing for the markers and for the rest of your group)

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

39 / 40

The End

Any questions?
Remember, the discussion forum on Piazza is at your disposal!

Useful books
The C Programming Language by Kernighan and Ritchie
Prentice Hall, 2nd edition
C Traps and Pitfalls by Andrew Koenig
Addison Wesley, 1st edition

Ioannis Papagiannis, Pedro Mediano, Feroz Salam, Mark


C andWheelhouse
Data Structures
(Imperial
in Pintos
College London)

January 2016

40 / 40

Вам также может понравиться