F6 Skapa C program

F6 Skapa C program

Ett C-program skapas i olika steg. Först sker preprocessor instruktioner. Dessa opererar enbart på källkodstexten och används t.ex. för att inkludera standard-bibliotekets API. Efter preprocessorn sker kompilering och assemblering. Då bildas en objekt modul med ändelsen ’.o’. Objektfilerna inndehåller maskinkod. I sista skedet länkas de olika objektmodulerna ihop till ett körbart program som på unix-system får ändelsen .out och på windows .exe

Preprocessorn

Preprocessorinstruktioner börjar med tecknet ’#’. Instruktionerna opererar enbart på texten. Med #define kan man definera konstanter och makron. T.ex.

#define PI 3.14
#define PRINTLN(x) printf(x"\n");

Man kan inkludera header-filer som innehåller funktionsdeklarationer (jämför med pythons import) för att få tillgång till färdiga definitioner. Preprocessorn klistrar in texten. För att skydda sig mot att inkluderade filer inkluderar samma fil många gånger används följande konstruktion ofta kallad include-guard.

#ifndef REDAN_INKLUDERAT_PROGRAM
#define REDAN_INKLUDERAT_PROGRAM

#include “local_fil.h”	/* leta lokalt  */
#include <system_fil.h>	/* leta i systemet */

kod...

#endif

Länkning

I objektfilerna behöver inte maskinkod som behövs finnas med. Det finns kvar anrop till okänd maskinkod. Signaturerna för dessa anrop stod i de inkluderade header-filerna. Vid länkningen letas definitionerna till dessa anrop och hittas de inte får man länkningsfel. Det kan vara jobbigt att felsöka länkningsfel, felmeddelandet kan vara kryptiskt och man har inget att debugga.

Manualer

För att ta reda på mer om de anrop man kan göra finns ett hjälpprogram som heter man. Hjälp om printf får man genom att skriva man printf i ett terminalfönster (eller använda google ‘printf format’). Hjälptexten förutsätter oftast att den som läser är väl förtrogen med C och unix.

Makefile

För att bygga de olika modulerna används ett make- program som tar som indata en fil som heter Makefile, make kan känna av vilka filer som behöver kompileras om genom att jämföra tidsstämplarna på objektfilen och källkodsfilerna. En makefile beskriver beroenden mellan olika mål (targets) och instruktioner som ska utföras.

FLAGS = -W -g 

all:	nod.o program.o
	gcc $(FLAGS) -o utfil.exe nod.o program.o

program.o: program.c
	gcc $(FLAGS) -c program.c

nod.o:	nod.c nod.h
	gcc $(FLAGS) -c nod.c

# En regel för flera numrerade tester: make test03, make test01 etc
test0%:                     
	@echo Tillverkar test      # @ tar bort extra utskrift
     gcc –o test0$* test0$*.c   # $* matchar % i regeln

Uppdelning i header-filer och implentationsfiler

När man programmerar C så brukar man lägga implementation i .c-filer. I header-filerna (.h) läggs funktionsdeklarationer och eventuellt egendefinierade datatyper. Det som ligger i header-filerna är gränssnittet utåt mot användaren.

Ett C-program i delar.

Genomgång av ett C-program. Kompileringsfel, länkningsfel m.m.

nod.h

struct post {
    char name[29];
    float bmi;
    struct post * next;
};
typedef struct post Post;

void writePost(Post * p);

nod.c

#include "nod.h"
#include <stdio.h>

void writePost(Post * p) {
    printf("Namn: %s\nbmi: %f\n", p->name, p->bmi); 
}

program.c

#include <stdlib.h>
#include <stdio.h>

#include "nod.h"

int vikt;                   /* global variabel  */
static float lengd;         /* filglobal variabel */

int main(int argc, char * argv[]) {
    Post * p  = (Post *) malloc(sizeof(Post));
    p -> next = (Post *) malloc(sizeof(Post));

    printf("Vad heter du? ");
    fscanf(stdin, "%s", p->name);

    printf("Hur lång är du (m)? ");
    fscanf(stdin, "%f", &lengd);

    printf("Vad väger du (kg)? ");
    fscanf(stdin, "%d", &vikt);

    p -> bmi = vikt / (lengd * lengd);
    writePost(p);
    return 0;
}

test01.c

#include <stdio.h>

int main() {
  printf("Detta är test 1\n");
}