08 advanced techniques

36
1 Advanced Advanced Techniques Techniques C Foundation C Foundation

Upload: goodhackers

Post on 22-May-2015

204 views

Category:

Technology


3 download

DESCRIPTION

hihi

TRANSCRIPT

Page 1: 08 advanced techniques

11

AdvancedAdvancedTechniquesTechniques

C F

ou

nd

atio

nC

Fo

un

dat

ion

Page 2: 08 advanced techniques

22cl

ean

Ccl

ean

C• code that compiles in both C and C++code that compiles in both C and C++

C++ compiler is stricter than CC++ compiler is stricter than C e.g. pre C99 did not require function declarationse.g. pre C99 did not require function declarations e.g. C++ requires more conversions to be explicite.g. C++ requires more conversions to be explicit avoid C++ keywordsavoid C++ keywords

boolcatchclassconst_castdelete dynamic_castexplicitexportfalsefriendmutablenamespace

C++ keywords that are not also C keywordsC++ keywords that are not also C keywords

newoperatorprivateprotectedpublicreinterpret_caststatic_casttemplatethis throwtruetry

typeidtypenameusingvirtualwchar_t

Page 3: 08 advanced techniques

33co

mm

ents

com

men

ts• Comments can indicate missing codeComments can indicate missing code

void test_is_leap_year(void){ // years not divisible by 4 are leap years assert(is_leap_year(1906)); assert(!is_leap_year(2009));

// years divisible by 4 but not 100 are leap years assert(is_leap_year(1984)); assert(is_leap_year(2008));

// years divisible by 100 but not 400 are not leap years assert(!is_leap_year(1900)); assert(!is_leap_year(2100));

// years divisible by 400 are leap years assert(is_leap_year(2000)); assert(is_leap_year(2400));}

BEFOREBEFORE

Page 4: 08 advanced techniques

44co

mm

ents

com

men

ts• Imagine if C had no commentsImagine if C had no comments

void years_not_divisible_by_4_are_leap_years(void){ assert(is_leap_year(1906)); assert(!is_leap_year(2009));}void years_divisible_by_4_but_not_100_are_leap_years(void){ assert(is_leap_year(1984)); assert(is_leap_year(2008));}void years_divisible_by_100_but_not_400_are_not_leap_years(void){ assert(!is_leap_year(1900)); assert(!is_leap_year(2100));}void years_divisible_by _400_are_leap_years(void){ assert(is_leap_year(2000)); assert(is_leap_year(2400));}

AFTERAFTER

Page 5: 08 advanced techniques

55cl

arit

y ~

bre

vity

clar

ity

~ b

revi

ty• prefer initialization to assignmentprefer initialization to assignment

• don't explicitly compare against true/falsedon't explicitly compare against true/false

int count = 0;

int count;count = 0;

??

if (has_prefix("is") == true) ...

if (has_prefix("is")) ...

??

refactorrefactor

refactorrefactor

Page 6: 08 advanced techniques

66im

plic

it v

s ex

plic

tim

plic

it v

s ex

plic

t• avoid redundant use of true/falseavoid redundant use of true/false

bool is_even(int value){ if (value % 2 == 0) return true; else return false;}

bool is_even(int value){ return value % 2 == 0;}

??

this version is very "solution focused"this version is very "solution focused"

this version is less solution focused;this version is less solution focused;it is more problem focused;it is more problem focused;it is more "declarative"it is more "declarative"

refactorrefactor

Page 7: 08 advanced techniques

77im

plic

it v

s ex

plic

tim

plic

it v

s ex

plic

t• make inter-statement dependencies explicitmake inter-statement dependencies explicit

bool some_func(int value){ if (value % 2 == 0) return alpha(); return beta();}

bool some_func(int value){ if (value % 2 == 0) return alpha(); else return beta();}

??

consider if you accidentally refactor the if without consider if you accidentally refactor the if without the last return - oopsthe last return - oops

the return statements are now at thethe return statements are now at thesame indentation. logical == physicalsame indentation. logical == physical

refactorrefactor

Page 8: 08 advanced techniques

88lo

gic

vs

con

tro

llo

gic

vs

con

tro

l• in general, beware of boolean literalsin general, beware of boolean literals

if (oldest) if (last_access < cut_off) return true; else return false; else return false;

??

again, wordy, verboseagain, wordy, verbose

refactorrefactor

return oldest && last_access < cut_off;

much simpler, reads wellmuch simpler, reads well

Page 9: 08 advanced techniques

99h

ow

to

iter

ate

ho

w t

o it

erat

e• iteration is a common bug hotspotiteration is a common bug hotspot

looping is easy, knowing when to stop is tricky!looping is easy, knowing when to stop is tricky!

• follow the fundamental rule of designfollow the fundamental rule of design always design a thing by considering it in its next always design a thing by considering it in its next

largest contextlargest context what do you want to be true what do you want to be true afterafter the iteration? the iteration? this forms the termination conditionthis forms the termination condition

... search(size_t end, int values[], int find){ size_t at = 0;

// values[at==0 at==end] iteration

at == end || values[at] == find

...}

we didn't find it............we didn't find it............ ....................we found it....................we found it oror(short-circuiting)(short-circuiting)

Page 10: 08 advanced techniques

1010h

ow

to

iter

ate

ho

w t

o it

erat

e• the negation of the termination condition is the negation of the termination condition is

the iteration's continuation conditionthe iteration's continuation condition !(at == end || values[at] == find)!(at == end || values[at] == find) at != end && values[at] != findat != end && values[at] != find

• then simply fill in the loop bodythen simply fill in the loop body

... search(size_t end, int values[], int find){ size_t at = 0;

while (at != end && values[at] != find) { ... } ...}

equivalentequivalent(DeMorgan's Law)(DeMorgan's Law)

at++;

short-circuiting protects values[at] short-circuiting protects values[at]

Page 11: 08 advanced techniques

1111b

ad t

yped

efb

ad t

yped

ef• don't attempt to hide a pointer in a typedefdon't attempt to hide a pointer in a typedef

if it's a pointer make it look like a pointerif it's a pointer make it look like a pointer abstraction is about hiding abstraction is about hiding unimportantunimportant details details

typedef struct date * date;

bool date_equal(const date lhs, const date rhs);

??date.hdate.h

bool date_equal(const struct date * lhs, const struct date * rhs);

what is const?what is const?

bool date_equal(struct date * const lhs, struct date * const rhs);

is it the date object pointed to?is it the date object pointed to?

or is it the pointer?or is it the pointer?

Page 12: 08 advanced techniques

1212g

oo

d t

yped

efg

oo

d t

yped

ef

typedef struct date date;

bool date_equal(const date * lhs, const date * rhs);

date.hdate.h

struct date;

bool date_equal(const struct date * lhs, const struct date * rhs);

date.hdate.halternativesalternatives

no * hereno * here

Page 13: 08 advanced techniques

1313st

ron

g t

yped

efst

ron

g t

yped

ef• a typedef does a typedef does notnot create a new type create a new type

• consider using a wrapper type instead…consider using a wrapper type instead…

typedef struct { int value; } mile;typedef struct { int value; } kilometer;

typedef int mile;typedef int kilometer;

void strong(mile lhs, kilometer rhs){ lhs = rhs;}

void weak(mile lhs, kilometer rhs){ lhs = rhs; ...}

Page 14: 08 advanced techniques

1414w

eak

enu

mw

eak

enu

m• enums are very weakly typedenums are very weakly typed

an enum's enumerators are of type integer, not of an enum's enumerators are of type integer, not of the enum type itself!the enum type itself!

typedef enum { clubs, diamonds, hearts, spades } suit;

typedef enum { spring, summer, autumn, winter} season;

void weak(void){ suit trumps = winter;}

Page 15: 08 advanced techniques

1515st

ron

ger

en

um

sst

ron

ger

en

um

stypedef struct { int value; } suit;extern const suit clubs, diamonds, hearts, spades;

const suit clubs = { 0 }, diamonds = { 1 }, hearts = { 2 }, spades = { 3 };

typedef struct { int value; } season;extern const season spring, summer, autumn, winter;

void strong(void){ suit trumps = winter;}

season.hseason.h

suit.hsuit.h

const season spring = { 0 }, summer = { 1 }, autumn = { 2 }, winter = { 3 };

season.cseason.c

suit.csuit.c

Page 16: 08 advanced techniques

1616si

de

effe

cts

sid

e ef

fect

s• 5.1.2.3 Program semantics5.1.2.3 Program semantics

At certain specified points in the execution At certain specified points in the execution sequence called sequence points, sequence called sequence points, all all side effectsside effects of previous evaluations shall be of previous evaluations shall be

complete and complete and no no side effectsside effects of subsequent evaluations of subsequent evaluations

shall have taken placeshall have taken place

• what constitutes a side effect?what constitutes a side effect? accessing a volatile objectaccessing a volatile object modifying an objectmodifying an object modifying a filemodifying a file calling a function that does any of thesecalling a function that does any of these

Page 17: 08 advanced techniques

1717vo

lati

levo

lati

le• 6.7.3 Type qualifiers6.7.3 Type qualifiers

An object that has volatile-qualified type may be An object that has volatile-qualified type may be modified in ways unknown to the implementation modified in ways unknown to the implementation or have other unknown side effects. Therefore or have other unknown side effects. Therefore any expression referring to such an object shall any expression referring to such an object shall be evaluated strictly according to the rules…be evaluated strictly according to the rules…described in 5.1.2.3described in 5.1.2.3

int global;volatile int reg;... reg *= 1;

reg = global; reg = global;

int v1 = reg; int v2 = reg;...

reg looks unchanged but reg is reg looks unchanged but reg is volatile so an access to the object volatile so an access to the object is required. This access may cause is required. This access may cause its value to change.its value to change.

these cannot be optimized to athese cannot be optimized to asingle assignment.single assignment.

v1 might not equal v2.v1 might not equal v2.

Page 18: 08 advanced techniques

1818ex

erci

seex

erci

se

volatile int m;

void eg(void){ int value = m + m; ...}

• in this statement… where are the sequence points? where are the side-effects? is it undefined?

Page 19: 08 advanced techniques

1919d

epen

den

cies

dep

end

enci

es• #include dependencies are #include dependencies are transitivetransitive

if you change a .h file you have to recompile all if you change a .h file you have to recompile all files that #include it at any depthfiles that #include it at any depth

a visible reflection of the physical couplinga visible reflection of the physical coupling

#include "grommit.h"#include "flange.h"...typedef struct{ grommit w; flange f; ...} wibble_t;

#include "sink.h"#include "washer.h"...typedef struct{ sink dest; washer w; ...} grommit;

wibble_t.hwibble_t.h

grommit.hgrommit.h

sink.hsink.h

washer.hwasher.h

flange.hflange.h

Page 20: 08 advanced techniques

2020o

paq

ue

typ

eso

paq

ue

typ

es• an ADT implementation techniquean ADT implementation technique

a forward declaration gives the name of a typea forward declaration gives the name of a type the definition of the type – and it's accompanying the definition of the type – and it's accompanying

#includes – are #includes – are notnot specified in the header specified in the header all use of the type has to be as a pointer and all all use of the type has to be as a pointer and all

use of the pointer variable has to be via a functionuse of the pointer variable has to be via a function

...typedef struct wibble_tag wibble;

wibble * wopen(const char * filename);

int wclose(wibble * stream);...

wibble.hwibble.h

allall uses of wibble uses of wibblehave to be have to be as pointersas pointers

not definednot defined

minimal #includesminimal #includes

Page 21: 08 advanced techniques

2121m

od

ule

: u

sem

od

ule

: u

se• in most APIs the idea that a set of functions in most APIs the idea that a set of functions

are closely related is quite weakly expressedare closely related is quite weakly expressed

• a struct containing function pointers can a struct containing function pointers can express the idea more stronglyexpress the idea more strongly

int main(int argc, char * argv[]){ wibble * w = wibbles.open(argv[1]); ... wibbles.close(w);}

int main(int argc, char * argv[]){ wibble * w = wopen(argv[1]); ... wclose(w);}

Page 22: 08 advanced techniques

2222m

od

ule

: h

ead

erm

od

ule

: h

ead

er#ifndef WIBBLE_INCLUDED#define WIBBLE_INCLUDED......typedef struct wibble_tag wibble;

struct wibble_api{ wibble * (*open )(const char *); ... int (*close)(wibble *); };extern const struct wibble_api wibbles;

#endif

wibble.hwibble.h

Page 23: 08 advanced techniques

2323m

od

ule

: s

ou

rce

mo

du

le :

so

urc

e#include "wibble.h"......static wibble * open(const char * name){ ...}...

wibble.cwibble.c

static int close(wibble * stream) { ...};

const struct wibble_api wibbles = { open, ..., close};

no need to writeno need to write&open, &close&open, &close

static linkagestatic linkage

Page 24: 08 advanced techniques

2424A

DT

AD

T• opaque type memory management…opaque type memory management…

clients cannot create objects since they don't clients cannot create objects since they don't know how many bytes they occupyknow how many bytes they occupy

#include "wibble.h"

void client(void){ wibble * pointer; ... wibble value; ... ptr = malloc(sizeof(*ptr));}

...typedef struct wibble wibble;...

wibble.hwibble.h

Page 25: 08 advanced techniques

2525sh

ado

w d

ata

typ

esh

ado

w d

ata

typ

e• an ADT can declare its size!an ADT can declare its size!

clients can now allocate the memoryclients can now allocate the memory true representation remains abstracttrue representation remains abstract

typedef struct wibble{ unsigned char size[16];} wibble;

bool wopen(wibble *, const char *);void wclose(wibble *);

wibble.hwibble.h

#include "wibble.h"void client(const char * name){ wibble w; if (wopen(&w, name)) ... wclose(&w);}

Page 26: 08 advanced techniques

2626sh

ado

wed

typ

esh

ado

wed

typ

e• implementation needs to…implementation needs to…

define the true representation typedefine the true representation type

wibble.cwibble.c

#include "grommit.h"#include "flange.h"

typedef struct{ grommit g; flange f; ...} wibble_rep;

typedef struct wibble { unsigned char size[16];} wibble;

wibble.hwibble.h

the analogy is that thethe analogy is that thetrue type caststrue type castsa shadow which a shadow which reveals only its sizereveals only its size

Still some problemsStill some problemsthough…though…

Page 27: 08 advanced techniques

2727p

rob

lem

1p

rob

lem

1• the size of the type must not be smaller than the size of the type must not be smaller than

the size of the type it shadowsthe size of the type it shadows assert only works at runtimeassert only works at runtime it would be safer to check at compile timeit would be safer to check at compile time

typedef struct wibble { ...} wibble;

wibble.hwibble.h

typedef struct{ ...} wibble_rep;

wibble.cwibble.c

assert(sizeof(wibble) >= sizeof(wibble_rep))

Page 28: 08 advanced techniques

2828d

eep

mag

icd

eep

mag

ic• use a compile time assertionuse a compile time assertion

you cannot declare an array with negative sizeyou cannot declare an array with negative size

#define COMPILE_TIME_ASSERT(desc,exp) \¬ extern char desc [ (exp) ? 1 : -1 ]

compile_time_assert.hcompile_time_assert.h

#include "compile_time_assert.h"COMPILE_TIME_ASSERT(ok, 1 == 1);

#include "compile_time_assert.h"COMPILE_TIME_ASSERT( your_message, 1 == 0);

gcc error: size of array 'your_message' is negative

Page 29: 08 advanced techniques

2929co

mp

atib

le s

ize

com

pat

ible

siz

e#include "wibble.h"#include "flange.h"#include "grommet.h"#include "compile_time_assert.h"

typedef struct{ grommet g; flange f;} wibble_rep;

COMPILE_TIME_ASSERT( sizeof_wibble_not_less_than_sizeof_wibble_rep, sizeof(wibble) >= sizeof(wibble_rep));...

wibble.cwibble.c

Page 30: 08 advanced techniques

3030p

rob

lem

2p

rob

lem

2• the two types must be alignment compatiblethe two types must be alignment compatible

this means the first member of both types must be this means the first member of both types must be alignment compatiblealignment compatible

typedef struct{ grommit g; flange f; ...} wibble_rep;

wibble.cwibble.c

typedef struct wibble { unsigned char size[16];} wibble;

wibble.hwibble.h

Page 31: 08 advanced techniques

3131al

ign

men

t so

luti

on

alig

nm

ent

solu

tio

n• use a union to force alignmentuse a union to force alignment

typedef union{ char c,*cp; int i,*ip; long l,*lp; long long ll,*llp; float f,*fp; double d,*dp; long double ld,*ldp; void *vp; void (*fv)(void); void (*fo)(); void (*fe)(int,...);} alignment;

#include "alignment.h"...typedef union wibble{ alignment universal; unsigned char size[16];} wibble;...

alignment.halignment.h

wibble.hwibble.h

List all the primitive types in here. List all the primitive types in here. One must have the strictest alignmentOne must have the strictest alignment

Page 32: 08 advanced techniques

3232p

rob

lem

3p

rob

lem

3• unions are much rarer than structsunions are much rarer than structs

design is as much about design is as much about useuse as implementation as implementation

6.7.2.3 Tags6.7.2.3 TagsParagraph 1, sentence 2Paragraph 1, sentence 2Where two declarators that use the same tag declare Where two declarators that use the same tag declare the same type, they the same type, they shallshall both use the same choice both use the same choice of struct, union, or enum.of struct, union, or enum.

typedef struct wibble wibble;...

client.hclient.hforward declarationforward declaration

Oooops: it's a union not a structOooops: it's a union not a struct

Page 33: 08 advanced techniques

3333w

rap

per

str

uct

wra

pp

er s

tru

ct• put a union object inside a struct!put a union object inside a struct!

drop the union tag namedrop the union tag name

6.7.2.3 Tags6.7.2.3 TagsParagraph 4, sentence 2Paragraph 4, sentence 2Each declaration of a structure, union, or Each declaration of a structure, union, or enumerated type which does not include a tag enumerated type which does not include a tag declares a distinct typedeclares a distinct type

...typedef struct wibble { union { alignment universal; unsigned char size[16]; } shadow;} wibble;...

wibble.hwibble.h

one objectone object

Page 34: 08 advanced techniques

3434co

nve

rsio

ns

1co

nve

rsio

ns

1• conversion can be via memcpyconversion can be via memcpy

helper function allows assignmenthelper function allows assignment

wibble.cwibble.c

wibble.cwibble.c

static inline wibble shadow(wibble_rep * src){ wibble dst; memcpy(&dst, src, sizeof(*src)); return dst;}

bool wopen(wibble * w, const char * name){ wibble_rep rep = { .g = ..., .f = ..., }; *w = shadow(&rep); ...;}

Page 35: 08 advanced techniques

3535co

nve

rsio

ns

2co

nve

rsio

ns

2• conversion can be via pointer castsconversion can be via pointer casts

helper function allows helper function allows operator operator

wibble.cwibble.c

static inline wibble_rep * rep(wibble * w){ return (wibble_rep *)w;}

void wclose(wibble * w);{ rep(w)->g = ...; rep(w)->f = ...; ...}

Page 36: 08 advanced techniques

3636C

on

tact

Co

nta

ct• This course was written byThis course was written by

Jon Jagger

Expertise: Agility, Process, OO, Patterns

Training+Designing+Consulting+Mentoring

www.jaggersoft.com

jon@ jaggersoft.com

{ JSL }