Transcript Slide 1

1
Krasjkurs i C (pluss litt
matlab)
2
Innhold
– Litt om Matlab
– Funksjoner
– Strukturer (Structs)
– Noen matlab-funksjoner dere kan få bruk for
– C
–
–
–
–
–
–
–
–
–
–
–
Kompilatorer
Kompilering
C syntaks
Funksjoner i C
Variable i C
Operatorer i C
Pekere
Arrays og Strukturer
Makroer
Dynamisk Minne-allokering
Lesing og skriving av binær fil, eksempel på å lese
en wav-fil i C. (Nyttig for oppgaven..!)
Om du ønsker, kan du sette inn navn, tittel på foredraget, o.l. her.
3
Matlab
– Antar en del kunnskap i matlab: For mer
grundig introduksjon henvises til:
http://www.iet.ntnu.no/~gjendems/docume
nts/MatlabIntro.pdf
– Matlab skiller seg fra språk som java og C ved
at matlab prosesserer linje for linje,
– Matlab håndterer mange oppgaver, som du
selv må ha kontroll på i C! (håndtering av
datatyper, minneallokering o.l)
– Matlab er bra til simulering pga. enkel syntaks,
koden er enkel å debugge, og det finnes
mange funksjoner for visualisering av data.
– Matlab har mange ferdiglagde funksjoner, men
tenk på å skrive matlab kode som uten for
store endringer kan skrives om til C !
Om du ønsker, kan du sette inn navn, tittel på foredraget, o.l. her.
4
Funksjoner i Matlab
En funksjon er en “.m” fil som starter med function.
Funksjon kan ta variable inn, utføre en eller flere
operasjoner, og returnere et vilkårlig antall variable.
Akkurat som funksjoner i java eller C
Variabel (ev.
variable) som skal
returneres.
“geom()” er en funksjons-navnet.
Funskjonen må lagres som geom.m
function ssum =geom(a,N)
% funksjon som beregner summen til en
% geometrisk rekke
Funksjonsargumenter
n=0:N;
ssum= sum(a.^n)
Kommentarer i Matlab beynner med %
5
Strukturer i Matlab
struct: Ikke så forskjellig fra et objekt i java, men en struct er uten metoder.
En struct består av av felter med tilhørende verdier, der de forskjellige
feltene kan inneholde forskjellige datatyper.
>>opt=struct('gamma',0.9,'nbits',4,'stepsize',2.0)
opt =
gamma: 0.9000
nbits: 4
stepsize: 2
>> opt.gamma
Felter blir aksessert med ‘.’ notasjon.
ans =
0.9000
>> opt.alpha=0.9
Nye felter kan enkelt legges til.
opt =
gamma:
nbits:
stepsize:
alpha:
0.9000
4
2
0.9000
Struct er en grei datatype å bruke for å
samle tilhørende data.
6
Noen matlab-funksjoner dere
kanskje får bruk for
•
•
•
•
•
Wavrecord: Ta opp lyd i matlab.
Wavread: Les inn en ’wav’-fil til en vektor i matlab
Wavwrite: skriv en vektor til en ’wav’-fil
Soundsc: Spill av en vektor i matlab
Wavplay: Spill av en wavfil i matlab (Kan også gjøres med først
wavread og deretter soundsc)
• Randn: Generer normalfordelte tilfeldige tall i matlab, kan
brukes når støy-generatoren skal implementeres
Er du usikker på hvordan disse funskjonene
brukes, skriv help funksjonsnavn i matlab.
7
C-Kompilator
• C er i motseteting til matlab et kompilatorspråk på samme måte
som java (javac).
• C-kompilatorer finnes gratis tilgjengelig på internett. I prinsippet
kan dere bruke den dere liker best..
• Forslag:
– Gnu’s kompilator gcc.
• Denne er egentlig laget for unix, men kan kjøres på windows i et
program som heter cygwin
• Fremgangmåte i windows:
– Innstaller Cygwin
– Et tips er å legge katalogen hvor bin-filen til cygwin ligger (vanligvis
C:/cygwin/bin) i environment-variablen ”system path”, slik at kompilatoren
gcc kan kjøres uansett hvilken katalog man er i.
– Får du ikke kompilatoren til å fungere, kom å spør oss om hjelp! 
8
Kompilering med gcc
Kjør kompilatoren for å konvertere programmet fra
kildekoden til en binær kjørbar fil:
$ gcc my_program.c –o my_program
Opsjonen –o betyr at det lages en fil som heter
my_program.exe i windows, eventuelt
my_program.out i unix. Hvis ikke denne brukes lages
en fil med navn a.out (som er default)
Kan programmet ha mer
enn en c fil?
Det kan være lurt å lage en makefil som definerer
regler for kompilering og lenking av alle filer som
inngår i et program. Da kan hele systemet enkelt
kompileres med å skrive make. Mer om hvordan man
lager en slik makefil neste gang.
9
Kompilator
Preprosessering
#include <stdio.h>
Kompileringer skjer i to steg:
Preprossesering og kompilering.
/* The simplest C Program */
int main(int argc, char **argv)
{
printf(“Hello World\n”);
return 0;
}
__extension__ typedef
unsigned long long int
__extension__ typedef
unsigned int
__uid_t;
__extension__ typedef
unsigned int
__gid_t;
__extension__ typedef
unsigned long int
__extension__ typedef
unsigned long long int
__extension__ typedef
unsigned int
__extension__ typedef
long int
__extension__ typedef
long long int
__dev_t;
__ino_t;
__ino64_t;
__nlink_t;
__off_t;
__off64_t;
extern void flockfile (FILE *__stream)
;
extern int ftrylockfile (FILE *__stream)
;
extern void funlockfile (FILE *__stream)
;
int main(int argc, char **argv)
{
printf(“Hello World\n”);
return 0;
}
Program
Kompilering
I preprossesering blir kildekoden ekspandert til
lengre kode som er enklere for kompilatorene å
forstå. Alle linjer som start med # blir tolket av
preprosessoren
• #include inkluderer en fil.
• #define definerer en makro.
• Kommentarer blir fjernet ( /* */ , // )
• kodelinjer over flere linjer blir satt sammen til en
linje ( \ )
Kompilatoren endrer så teksten til binær kode
som CPU’en kan kjøre direkte
10
C Syntax, og Hello World
Hva menes med
<>?
#include setter inn en fil. “.h” filer er såkalte “header-filer”. Header-filer
definerer grensenittet (interface i java) til bibliotek og kode i andre c-filer.
stdio.h er et av de vanligste biliotekene brukt u C, og inneholder
funskjoner for standard input and output.
#include <stdio.h>
/* The simplest C Program */
Kommentarer i C beynner med /* og avsluttes
med */.
int main() funksjonen er alltid! Det
stedet hvor programmet starter å
kjøre. (Uavhengig hvor main
funksjonen finnes i koden)
int main(int argc, char **argv)
{
printf(“Hello World\n”);
return 0;
}
Returner ‘0’. main() returnerer enten
0 eller 1, der programmet kan
returnere 1 til operativsystemet hvis
det har oppstått en feil.
Blokker med kode markeres med {
… }. En blokk eller et skop har
egne lokale variable, som bare er
tilgjengelige innenfor blokken
Skriv ut en melding til “stdout”. ‘\n’ betyr ny
linje. Alle “Statements” må avsluttes med
semikolon.
11
Funksjoner
Funksjoner i C er veldig likt funksjoner i java. Man sender
Argumenter til funksjonen og den retunerer en Verdi.
Return type, or void
#include <stdio.h>
/* The simplest C Program */
int main(int argc, char **argv)
{
printf(“Hello World\n”);
return 0;
}
Returnering av
verdi
“main()” er en funksjon.
Funksjonsargumenter
Å kalle en funksjon “printf()” er bare en
annen funksjon, som main(). Den er
definert i “biblioteket” stdio.h, en samling
funksjoner som kan kalles fra
programmet.
12
Hva er en Variabel
Symbol-tabell
En Variabel navngir en plass i minnet hvor
man lagrer en Verdi av en bestemt
Datatype.
Man Deklarerer en variabel ved å gi den et
navn og ved å spesifisere datatypen,
eventuelt kan man sette en initialverdi
(startverdi)
char x;
char y=‘e’;
Initiell verdi til x er udefinert
Addr
Hvilke navn kan
brukes?
Datatypen er en enkelt char
(“character”)
extern? static? const?
Verdi
0
1
2
3
x
4
?
y
5
‘e’ (101)
6
Initiell verdi
Navn
Symbol
7
Kompilatoren legger dem
et sted i minnet.
8
9
10
11
12
13
Hva er minne?
Addr
Value
0
Datamaskin-minne kan sammenlines med
en stor tabell med nummererte bokser.
1
2
Nummeret til boksen er Addressen.
En byte kan lagres i hver boks
3
4
‘H’ (72)
Noen “logiske” datatyper bruker mer enn
en boks, slik som strengen “Hello\n” som
består av flere “charcters”, altså en tabell
av datatypen char.
5
‘e’ (101)
6
‘l’ (108)
7
‘l’ (108)
En Datatype navngir en logisk måte å lagre
verdier i minnet of memory. Noen
datatyper er:
8
‘o’ (111)
9
‘\n’ (10)
10
‘\0’ (0)
char
char [10]
int
float
int64_t
en enkelt char (1 slot)
En tabell med 10 char’s
signed 4 byte integer
4 byte floating point
signed 8 byte integer
11
Ikke alltid…
Signed?…
12
72?
14
Mer om datatyper og minne.
Symbol
Value
0
Forskjellige datatyper bruker forskjellige
mengde minne. De fleste datamaskinarkitekturer lagrer på et heltallig multiplum
av størrelsen på en primitiv
datatype.(int,char)
char x;
char y=‘e’;
int z = 0x01020304;
Addr
1
2
3
x
4
?
y
5
‘e’ (101)
“padding”
6
7
0x betyr at konstanten er
skrevet i hex (16tallsystem,0..9,A..,F)
En “vanlig” int bruker
4 bytes (dvs 32 bit
integer)
z
8
4
9
3
10
2
11
1
12
15
Skopet til en variabel
Alle Variable er definert innefor et “skop”. En
Variabel kan ikke refereres utenfor dette
skopet.
Skopet til en variabel defineres med
klammeparanteser { }, som i java, og tilsvarer
begin-end i matlab. Kalles også en blokk
Skopet til funksjons-argumentene er kun
inne i funskjonen, dvs. innenfor
klammeparantesene til funksjonen.
(Returner
ingenting)
void p(char x)
{
/*
char y;
/*
char z;
/*
}
/*
char z;
/*
p,x,y */
p,x,y,z */
p */
p,z */
void q(char a)
{
char b;
/* p,z,q,a,b */
Skopet til variablene definert inne i en
funksjon starter ved definisjonen og slutter
ved slutten av
Skopet til variable definert utenfor
funksjonen starter ved definisjonen og
slutter på slutten av filen, kalt gloable
variable.
p,x */
{
char c;
char b?
/* p,z,q,a,b,c */
}
legal?
char d;
/* p,z,q,a,b,d (not c) */
}
/* p,z,q */
16
Sammenligning og
matematiske operatorer
==
<
<=
>
>=
!=
&&
||
!
equal to
less than
less than or equal
greater than
greater than or equal
not equal
logical and
logical or
logical not
+
*
/
%
plus
minus
mult
divide
modulo
&
|
^
~
<<
>>
bitwise and
bitwise or
bitwise xor
bitwise not
shift left
shift right
Obs: Deling:
• Hvis andre argument er integer, så
vil resultatet bli integer !! (rounded):
5 / 10  0 , mens 5 / 10.0  0.5
Obs: Forskjell på & and &&..
1 & 2  0 mens 1 && 2  <true>
17
Mer om operatorer i C
x = y
x++
++x
x---x
assign y to x
post-increment x
pre-increment x
post-decrement x
pre-decrement x
x
x
x
x
x
+=
-=
*=
/=
%=
y
y
y
y
y
assign
assign
assign
assign
assign
(x+y)
(x-y)
(x*y)
(x/y)
(x%y)
to
to
to
to
to
x
x
x
x
x
Merk forskjellen på ++x og x++:
int x=5;
int y;
y = ++x;
/* x == 6, y == 6 */
int x=5;
int y;
y = x++;
/* x == 6, y == 5 */
Ikke bland tilordningsoperator =, og sammenligningsoperator ==
int x=5;
if (x==6)
/* false */
{
/* ... */
}
/* x is still 5 */
int x=5;
if (x=6)
/* always true */
{
/* x is now 6 */
}
/* ... */
18
“While” og “for” syntaks i C
“for” løkka kan ses på som en kortversjon av en while-stuktur
float pow(float x, uint exp)
{
float result=1.0;
int i;
i=0;
while (i < exp) {
result = result * x;
i++;
}
return result;
}
int main(int argc, char **argv)
{
float p;
p = pow(10.0, 5);
printf(“p = %f\n”, p);
return 0;
}
float pow(float x, uint exp)
{
float result=1.0;
int i;
for (i=0; (i < exp); i++) {
result = result * x;
}
return result;
}
int main(int argc, char **argv)
{
float p;
p = pow(10.0, 5);
printf(“p = %f\n”, p);
return 0;
}
19
Kan en funksjon modifisere
argumentene?
Hva om vi ønsket å implementere en funksjon pow_assign()
som modifiserer argumentet, slik at disse er ekvivalente:
float p = 2.0;
/* p is 2.0 here */
p = pow(p, 5);
/* p is 32.0 here */
Ville dette fungere?
void pow_assign(float x, uint exp)
{
float result=1.0;
int i;
for (i=0; (i < exp); i++) {
result = result * x;
}
x = result;
}
float p = 2.0;
/* p is 2.0 here */
pow_assign(p, 5);
/* p is 32.0 here */
Nei! I C, blir alle argumenter
sendt som verdier, og
skopet til den modifiserte
variabelen er bare innenfor
funskjonen
Men, hva om vi sendte
argumentet som adressen
til variabelen?
20
Å sende adresser
Symbol
Hva om vi hadde en måte å finne
adressen til en variabel, og så
referere til minnet med adressen.
Addr
Value
0
1
2
3
address_of(y) == 5
memory_at[5] == 101
void f(address_of_char p)
{
memory_at[p] = memory_at[p] - 32;
}
char y = 101;
/* y is 101 */
f(address_of(y)); /* i.e. f(5) */
/* y is now 101-32 = 69 */
char x
4
‘H’ (72)
char y
5
‘e’ (101)
6
7
8
9
10
11
12
21
En ny datatype: Pekere
Dette er akkurat hvordan pekere virker.
En “peker type”: peker til char
“addressen til”/ referingsoperator: &
“verdien til”/ dereference operator: *
void f(address_of_char p)
{
memory_at[p] = memory_at[p] - 32;
}
void f(char * p)
{
*p = *p - 32;
}
char y = 101;
/* y is 101 */
f(address_of(y)); /* i.e. f(5) */
/* y er nå 101-32 = 69 */
char y = 101;
/* y is 101 */
f(&y);
/* i.e. f(5) */
/* y er nå 101-32 = 69 */
Pekere brukes i C for til mange ting:
• Sende store objekter uten å kopiere dem
• Aksessere dynamisk allokert minne
• Referere til funksjoner
22
Eksempel på pekere
“Pointers”
“addressen til” :
“verdien til”: *
&
Input er en peker til char
void f(address_of_char p)
{
memory_at[p] = memory_at[p] - 32;
}
void f(char * p)
{
*p = *p - 32;
}
char y = 101;
/* y is 101 */
f(address_of(y)); /* i.e. f(5) */
/* y is now 101-32 = 69 */
char y = 101;
/* y is 101 */
f(&y);
/* i.e. f(5) */
/* y is now 101-32 = 69 */
En tommelfinger-regel er at hvis input-variablene som
sendes til funksjonn skal endres i funksjonen, må de
sendes som pekere. Hvis de ikke endres bør de sendes til
funksjonen som verdier.
NB!: Bruker man pekere som input til funksjoner er det
veldig viktig å huske å sende adressen og ikke verdien, da
man i tilfelle vil endre på en helt tilfeldig plass i minnet,
som kan føre til at hele systemet krasjer.
23
Eksmpel på pekere
int *p;
er en peker til en integer. En stjerne i forkant av variabelnavnet
deklarerer variabelen til å være en peker til den deklarerte typen (her int)
int *p , q
deklarerer en peker til int (p), og en int (q).
p=&q
lagrer adressen til q i p
int a;
a=*p
* er også dereferingsoperator, som betyr verdien til p, altså verdien som
ligger i addressen p peker på. I dette tilfellet vil altså variablen a få
verdien til q
24
Arrays
Arrays i C er en tabell med data av samme datatype, der data blir
lagt i minnet etter hverandre.
/* define an array of 10 chars */
char x[5] = {‘t’,’e’,’s’,’t’,’\0’};
/* accessing element 0 */
x[0] = ‘T’;
/* pointer arithmetic to get elt 3 */
char elt3 = *(x+3); /* x[3] */
/* x[0] evaluates to the first element;
* x evaluates to the address of the
* first element, or &(x[0]) */
/* 0-indksert */
#define COUNT 10
char y[COUNT];
int i;
for (i=0; i<COUNT; i++) {
/* process y[i] */
printf(“%c\n”, y[i]);
}
[5] spesifiserer antallet elementer.
Initielle verdier kan settes I { }.
Arrays i C er 0-indeksert (her, 0..9)
x[3] == *(x+3) == ‘t’
Hva er forskjellen på
char x[count] og char
*x?
Symbol
Add
r
Value
char x
[0]
100
‘t’
char x
[1]
101
‘e’
char x
[2]
102
‘s’
char x
[3]
103
‘t’
char x
104
‘\0’
25
Repetisjon, pekere og arrays
int main(int argc,char **argv)
{
int *p ; int a=5;
p=&a
printf("Addressen til p: %d\n",p);
printf("Addressen til a: %d\n",&a);
printf("Verdien i p: %d\n",(*p));
printf("Addressen til p: %d\n",(&p));
Når a settes til p, blir a lik adressen lagret i p,
som ofte er et veldig stort tall. Kompilatoren vil
gi en warning om at et int blir satt til en
pekerverdi uten ”casting”.
a=p; /* Kompilator gir warning!*/
printf("Verdien til a: %d\n",&a);
Selv om ikke a er en peker kan
addressen refereres med &a
a=3;
printf("Verdi til p: %d\n",(*p));
printf("Verdien p[0]!: %d\n",p[0]);
Setter a til verdien 3, som også medfører
at p peker på verdien 3. (p peker på a).
int c[5]; c[0]=0; c[2]=2;
printf("Verdien til \"c\": %d\n",c);
printf("addressen til c: %d\n",&c);
printf("addressen c[0]: %d\n",(&c[0]));
printf("addressen c[1]: %d\n",&c[1]);
printf("addressen c[2] : %d\n",&c[2]);
printf("Verdi c[0]: %d\n",c[0]);
printf("Verdi c[2]: %d\n",c[2]);
return 0;}
Selv om p ikke er definert som et array kan p
tolkes som et endimensjonalt array, og
verdien til p kan refereres med p[0].
c=&c=&c[0] som er adressen til det første
elementet. c er altså egentlig en peker til det
første elementet arrayet .
26
Lese og skrive til fil
Før en fil kan bli aksessert, må den åpnes med fopen. Fopen returner en
peker til en definert datatype FILE (eller en null-peker hvis noe går galt)
int main(int argc,char **argv)
{
FILE *f,*f_new; /*2 filpeker2*/
long offset=44;
f=fopen("ae_a01.wav","rb");
f_new=fopen(“test.wav",“wb");
fseek(f,offset,0);
’rb’ vil si å åpne en binær fil for lesing, ’wb’ for å åpne
for skriving. (Og ev. lage filen hvis den ikke eksisterer)
En “.wav” inneholder 44 bit som er info om
lydfilen. (Samplefrekvenes o.l, som
egentlig også burde vært lest). For å lese
selve taledataene flyttes “posisjonen” til
filpekeren med funksjonen fseek. Dataene
I en wav-fil er normalt int16 (16 bits int),
dvs. en short i C (2 byte).
short value[1]; /*buffer*/
for (int i=0;i<100; i++)
{
fread(&value,sizeof(short),1,f);
printf("%d\n",value[0])
fwrite(&value,sizeof(short),1,f_new);
}
Funksjonen fread tar inn en adresse/peker (&value), og
fclose(f);
return 0;
leser N (i dette tilfellet 1) * size (sizeof(short)) fra filen
definert med filpekeren f.
}
fclose lukker filen og sletter filpekeren.
27
Casting i C
Noen ganger ønsker man en variabel av en bestemt type (x bytes), og så tilordne
denne til en variabel av en annen datatype (y bytes). Dette kalles “(type)casting”.
#include <stdio.h>
#include <math.h>
int main() {
char c;
int i;
float f;
c = 'a';
i = c;
f = i;
printf("c = %d (%c)\n",c,c);
printf("i = %d (%c)\n",i,i);
printf("f = %f\n", f);
double x=56.8890
int y,y2;
y=(int) x;
Y2=(int) round(x);
printf(”x = %lf\n", x);
printf(”y = %d\n", y);
printf(”y2 = %d\n", y);
int *p;
int q=5;
q=p; //kompilator gir warning
q=(int) p; //ingen warning
}
Enkle eksempler er å gjøre en char om til
en int, og en int om til en float.
Dette kan gjøres bare med vanlig
tilordning i C. Både i=c og f=i er en
”typecast”-operasjon.
Casting gjøres ved å skrive den nye typen
i parantes foran variabelnavnet.
En casting fra double/float til int gjør at
verdien bli rundet av nedover. (kutter
desimalene)
Selv om c gjør noen “typecasts”
automatisk, er det en god regel å “caste”
hvis vi er i tvil, som er en måte å si til
kompilatoren at vi (tror vi) vet hva vi holder
på med.
28
Strenger i C
En string i C er definert som en nullterminert array av char, det vil si en array av
typen char med en “0”-char til slutt for å definere slutten på strengen
#include <stdio.h>
#include <string.h>
int main(int argc,char **argv){
FILE *fp;
char id[5];
fp = fopen("h000001.wav","rb");
fread(id, sizeof(char), 4, fp);
De 4 første bytene i et en wav-fil, er av
typen char og inneholder tegnene: RIFF.
Hvis vi ønsker å lese inn de 4 første bytene
og lagre dem i en streng trenger vi en tabell
av størrels 5, i og med at vi må ha en
”nullbyte” til slutt!
id[4]=’\0’; //id[4]=0x00; id[4]=0;
if (strcmp(id, "RIFF")){
printf(“Dette er en Wavfil”)
/* Noen flere strenger */
const char* navn1=”Hans”;
char navn2[10]={’H’,’a’,’n’,’s’,’\0’}
navn2=”Petter”; /* Ikke mulig!’/
navn2[4]=’a’;
navn2[5]=’\0’;
printf(”%s\n”,navn2);
}
Det er flere måter å definere en streng på I
C. Men obs! Forskjell på initsialiserig av en
streng og tilordning,
En streng må håndteres som en array av
char..!
29
Strukturer
struct: En måte å sette sammen eksisterende typer til en struktur.
#include <sys/time.h>
/* declare the struct */
struct my_struct {
int counter;
float average;
struct timeval timestamp;
uint in_use:1;
uint8_t data[0];
};
/* define an instance of my_struct */
struct my_struct x = {
in_use: 1,
timestamp: {
tv_sec: 200
}
};
x.counter = 1;
x.average = sum / (float)(x.counter);
struct my_struct * ptr = &x;
ptr->counter = 2;
(*ptr).counter = 3; /* equiv. */
Pakking?
structen timeval er definert i denne h-filen.
En struct definerer en struktur med fields
En struct kan inneholde andre structer
Fields kan spesifisere spesifikke bitstørrelser.
A ny-definert struct initialiseres med
klammeparanteser. Alle felt som ikke blir
satt, blir satt til 0
Fields blir aksessert med ‘.’ notasjon.
En peker til en struct. Felter blir
aksessert med ‘->’ notasjon, eller
(*ptr).counter
30
Input fra kommandolinja
#include < stdio.h>
#include < stdlib.h>
int main(int argc, char** argv)
/*f.eks c:\ cmdline -a 2 -b 3.0
kjører programmet cmdline*/
/* main vil motta
argc=7
argv[0]=cmdline
argv[1]=-a
argv[2]=2
argv[3]=-b
argv[4]=3.0
*/
/* Start at i = 1 to skip the cmd name.*/
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {//check next char
switch (argv[i][1]) {
case 'a': a_value=atoi(argv[++i]);break;
case 'b': b_value=atof(argv[++i]);break;
default: fprintf(stderr, "Unknown switch
%s\n", argv[i]);
}
}
}
Funksjonene atoi og atof er
definert i stdlib.h og konverterer
en streng til hhv. int og double
main-funksjonen tar inn to variable fra
kommandolinja ved definsjon, argc er antall
strenger som er blitt skrevet, mens char **
argv er en peker til streng, og kan ses på
som en tabell av strenger. ”argv” inneholder
alle strenger som er blitt skrevet på
kommandolinja, inkludert programnavnet(argv[0])
En vanlig konvensjon for input-parametre, er
å angi en input med en ”switch” som vil si en
”-” og så et navn for opsjonen. Deretter
kommer verdien som ønskes som input til
programmet.
Å navngi input-opsjonene er bra for at
programmet skal kunne håndtere inputverdiene på en robust måte, samtidig som
det er brukervennlig.
31
Makroer
Makroer blir utført av preprosessoren i kompilatoren, som ekspanderer
koden ved å sette inn de definerte makroene.
Makroer er en måte å gjøre koden lettere å lese gjør koden lettere å
lese, men hvis mulig: bruk heller en static inline funksjon.
Makroer og static inline funksjoner må inkluders i en hver fil som
bruker dem, som regel ved en header-fil. Vanlig bruk for makroer:
/* Makroer brukes for å definere kontsanter */
#define FUDGE_FACTOR
45.6
#define MSEC_PER_SEC
1000
#define INPUT_FILENAME “my_input_file”
Float konstanter må ha et komma,
ellers er de av typen int
/* Makroer brukes for å gjøre aritmetikk med konstanter */
#define TIMER_VAL
(2*MSEC_PER_SEC)
Sett beregningene i parentes.
/* Makroer brukes for å hente informasjon fra kompilatoren */
#define DBG(args...) \
Makroer over
do { \
fprintf(stderr, “%s:%s:%d: “, \
opp med \
__FUNCTION__, __FILE__, __LINENO__); \
fprintf(stderr, args...); \
} while (0)
Hvorfor?
flere linjer må deles
Sett makroer over flere linje i do{}while(0)
/* ex. DBG(“error: %d”, errno); */
32
Typedef og noen ”Modifiers”
• Det er mulig å definere egne typer ved å bruke typedef
• Nye typer kan være helt nye typer som f.eks en struct, eller de
kan være en alias for en annen standard type.
• Det er regnet som god praksis å bruke store bokstaver for en ny
type definert med typedef: f.eks: typedef char* STRING;
• ”Auto” og ”Static”: Ved default blir en variabel i en funksjon
definert som auto. C genererer autovariable når funksjonen blir
kalt, og sletter dem igjen når funksjonen har returnert.
• Hvis man ønsker at en variabel definert i en funksjon ikke skal
bli slettet, må den defineres som static. Dette må brukes hvis
f.eks funksjonen returnerer en peker til en variabel definert inne i
funksjonen.
• Variable som blir deklarert utenfor en funksjon blir definert som
static ved default.
• En funksjon som defineres som static betyr noe helt annet. En
static funksjon kan bare kalles i den filen hvor den er definert.
• En variabel definert som const, betyr at den ikke kan brukes på
venstre-siden i en tilordning.
33
Enkel Makefile
Gitt et system med to c-filer og en header fil: hellomake.c,
hellofunc.c og hellofunc.h
#include “c:/cpath/hellofunc.h"
int main() {
//Kall en funksjon fra en annen fil
myPrintHelloMake();
return(0);
}
Program som kaller en funksjon fra cfilen hellofunc. Dette systemet kan enkelt
kompileres med:
gcc hellomake.c hellofunc.c –o hellomake
En makefil er en fil som inneholder regler for hvordan systemet skal
kompileres. Et program, som heter make, leser filen med navn “makefile”
(default), og utfører de kompilerings-reglene som er definert i makefilen. Det
vil si at hvis du har laget en makefil, kan du kompilere ved å kjøre make! Den
enkleste makefilen som kan lages for dette systemet er:
hellomake: hellomake.c hellofunc.c
gcc hellomake.c hellofunc.c –o hellomake –I .
Den første linjen inneholder alle filer programmet er avhengig av. Dette bruker
make til bare å kompilere de filer som er endret siden sist. NB: make krever en
tab før hver linje som den skal utføre.
34
Forts. Makefile
En litt mer kompilsert makefil:
CC=gcc
CFLAGS=-I.
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)
Nå er kompilatoren og flaggene definert som makroer (konstanter). Ved å sette
kompilatoren til å være avhengig av o-filene, så vet make at den må kompilere cfilene først, og så lenke filene etterpå. Denne typen makefil er bra nok for et lite
prosjekt, men en ting mangler…, avhengigheten til h-filen!
CC=gcc
CFLAGS=-I .
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
gcc -o hellomake hellomake.o hellofunc.o -I.
Makroen ($deps) inneholder all h-filene som c-filene avhenger av. Så lager vi en
regel som sier at o-filene avhenger av c-filene og h-filene i $(deps), og at make
skal generere o-filene som make trenger for å kompilere c-filene. –c flagget i gcc
betyr kompiler men ikke link, –o $@ betyr alle filene til venstre for :, og $< betyr
den første filen i avh.-listen.
35
Dynamsk Minne-allokering
Så langt har alle eksemplene allokert variable statisk ved å definere
dem i programmet.
Men hva om vi ønsker å allokere variable basert på dynamiske
hendelser/input mens programmet kjøres? Dette krever dynamisk
allokering.
Funksjonen malloc(N) allokerer minne
for N bytes
calloc(N,k) allokerer minne
for N elementer av en størrelse k.
NB! Minne som allokeres dynamisk må senere frigjøres med
funksjonen free()
36
Fallgruver med dynamisk
minne
Ved allokering av dynamisk minne, må man planlegge hvordan minnet
senere skal bli frigjort. Allokert minne som man mister “kontakt” med kalles
“memory leak”, og betyr at programmet “spiser” minne.
Garbage collection
Det er lett å glemme en peker til dynamisk minne som har blitt frigjort. Når
man frigjør dynamisk minne, er det sikrest å slette alle pekere til det.
Fordi dynamiske minne alltid bruker pekere, er det ingen måte for
kompilatoren å sjekke at bruken av minnet er riktig, dette betyr at feil som
kan detekteres med statisk allokering, ikke kan oppdages med dynamisk
allokering.