Citat:
Du anger helt enkelt flera fil-argument (c-filer) till kompilatorn:
gcc fil1.c fil2.c fil3.c (osv.)
(byt ut "gcc" mot "clang" om du kör clang)
Lite förenklat kan man säga att kompilatorn kompilerar varje källkodsfil var för sig utan att ta hänsyn till någon av de andra källkodsfilerna. Det betyder att fil1.c inte har någon aning om vad som finns i fil2.c (och vice versa). Om du exempelvis har en funktion i fil2.c som du vill kunna anropa i fil1.c brukar man skriva en header-fil som deklarerar vad som finns i fil2.c och sedan inkluderar man denna header-fil inuti fil1.c.
Låt oss skapa ett exempelprogram som består av två källkodsfiler, foo.c och bar.c:
foo.c:
bar.c:
I bar.c (i main-funktionen) anropar vi alltså funktionen "add" som finns definierad i filen foo.c.
Låt oss försöka kompilera ovanstående program som alltså består av två filer, foo.c och bar.c:
Ajdå! Kompilatorn varnar att bar.c inte vet vad "add" är för funktion. Vi behöver berätta för bar.c
vad "add" är för funktion. Dvs: Vad funktionen heter, hur många parametrar och vilken datatyp respektive parameter har och vilken retur-datatyp den har). Detta gör vi med en funktionsdeklaration, dessa skrivs normalt i en header-fil (om funktionen behöver anropas från en annan fil, annars kan man skriva den direkt i c-filen). Header-filen som tillhör en .c-fil döps normalt till samma namn som c-filen men med filändelsen .h istället för .c, detta är dock bara en konvention, du kan döpa h-filen till vad du vill.
Låt oss skapa header-filen foo.h (i samma mapp där bar.c och foo.c redan ligger) med en funktionsdeklaration för funktionen "add":
foo.h:
Vi kan nu inkludera header-filen (foo.h) inuti bar.c så bar.c vet vad "add" är för funktion.
Vi gör detta genom att lägga till #include "foo.h" i början av bar.c:
bar.c: (ny)
Låt oss nu kompilera programmet en gång till:
Vi ser att programmet kompileras utan problem.
Och när vi kör programmet (a.out) skrivs också talet 9 ut som förväntat.
----------------
Din fil "filhantering.c" ser lite konstig ut. Borde den inte innehålla två funktioner, en för att läsa fordon från fil och en funktion för att skriva fordon till fil? Nu ligger all kod i en enda funktion som heter "read_fordon"...
Sen kommer du behöva bryta ut en del definitioner och deklarationer till en extra header-fil eftersom filhantering.c behöver veta vad tillexempel "ANTAL_MAX_FORDON" och "f" är för något. Och filhantering.c kommer själv behöva en tillhörande header-fil (filhantering.h) så andra källkodsfiler kan anropa dess funktioner. Och du behöver såklart inkludera en del header-filer från standardbiblioteket i filhantering.c så den kan hitta "FILE", "memset()" och så vidare... Lycka till!
(Senaste koden du postat är uppdelad i tre källkodsfiler (filhantering.c, header.c och main.c), jag tror att du börjar snurra till det för dig själv nu. Börja med att dela upp koden i två källkodsfiler: filhantering.c och resten av koden i main.c (med tillhörande header-filer), sen när du fått detta att fungera kan du bryta upp koden i ytterliggare källkodsfiler om du tycker det skulle behövas.)
gcc fil1.c fil2.c fil3.c (osv.)
(byt ut "gcc" mot "clang" om du kör clang)
Lite förenklat kan man säga att kompilatorn kompilerar varje källkodsfil var för sig utan att ta hänsyn till någon av de andra källkodsfilerna. Det betyder att fil1.c inte har någon aning om vad som finns i fil2.c (och vice versa). Om du exempelvis har en funktion i fil2.c som du vill kunna anropa i fil1.c brukar man skriva en header-fil som deklarerar vad som finns i fil2.c och sedan inkluderar man denna header-fil inuti fil1.c.
Låt oss skapa ett exempelprogram som består av två källkodsfiler, foo.c och bar.c:
foo.c:
Kod:
int add(int a, int b) { return a + b; }
bar.c:
Kod:
#include <stdio.h> int main(void) { printf("%d\n", add(4, 5)); return 0; }
I bar.c (i main-funktionen) anropar vi alltså funktionen "add" som finns definierad i filen foo.c.
Låt oss försöka kompilera ovanstående program som alltså består av två filer, foo.c och bar.c:
Kod:
$ gcc foo.c bar.c bar.c:4:17: WARNING: Implicit declaration of function "add"
Ajdå! Kompilatorn varnar att bar.c inte vet vad "add" är för funktion. Vi behöver berätta för bar.c
vad "add" är för funktion. Dvs: Vad funktionen heter, hur många parametrar och vilken datatyp respektive parameter har och vilken retur-datatyp den har). Detta gör vi med en funktionsdeklaration, dessa skrivs normalt i en header-fil (om funktionen behöver anropas från en annan fil, annars kan man skriva den direkt i c-filen). Header-filen som tillhör en .c-fil döps normalt till samma namn som c-filen men med filändelsen .h istället för .c, detta är dock bara en konvention, du kan döpa h-filen till vad du vill.
Låt oss skapa header-filen foo.h (i samma mapp där bar.c och foo.c redan ligger) med en funktionsdeklaration för funktionen "add":
foo.h:
Kod:
Observera att en funktionsdeklaration ser ut som en funktionsdefinition med funktionskroppen utelämnad, man sätter också ett semikolon direkt efter parameterlistan.int add(int a, int b);
Vi kan nu inkludera header-filen (foo.h) inuti bar.c så bar.c vet vad "add" är för funktion.
Vi gör detta genom att lägga till #include "foo.h" i början av bar.c:
bar.c: (ny)
Kod:
#include "foo.h" #include <stdio.h> int main(void) { printf("%d\n", add(4, 5)); return 0; }
Låt oss nu kompilera programmet en gång till:
Kod:
Observera att vi anropar kompilatorn precis som innan, man ska alltså inte ange .h-filen på kommandoraden till kompilatorn, den inkluderas ju av bar.c.$ gcc foo.c bar.c $ ./a.out 9
Vi ser att programmet kompileras utan problem.
Och när vi kör programmet (a.out) skrivs också talet 9 ut som förväntat.
----------------
Din fil "filhantering.c" ser lite konstig ut. Borde den inte innehålla två funktioner, en för att läsa fordon från fil och en funktion för att skriva fordon till fil? Nu ligger all kod i en enda funktion som heter "read_fordon"...
Sen kommer du behöva bryta ut en del definitioner och deklarationer till en extra header-fil eftersom filhantering.c behöver veta vad tillexempel "ANTAL_MAX_FORDON" och "f" är för något. Och filhantering.c kommer själv behöva en tillhörande header-fil (filhantering.h) så andra källkodsfiler kan anropa dess funktioner. Och du behöver såklart inkludera en del header-filer från standardbiblioteket i filhantering.c så den kan hitta "FILE", "memset()" och så vidare... Lycka till!
(Senaste koden du postat är uppdelad i tre källkodsfiler (filhantering.c, header.c och main.c), jag tror att du börjar snurra till det för dig själv nu. Börja med att dela upp koden i två källkodsfiler: filhantering.c och resten av koden i main.c (med tillhörande header-filer), sen när du fått detta att fungera kan du bryta upp koden i ytterliggare källkodsfiler om du tycker det skulle behövas.)
Dessutom bör en c-fil alltid inkludera sin egen headerfil. Det garanterar att signaturen i headerfilen matchar den i implementationsfilen. En mismatch som annars antingen gett ett mer svårtytt länkfel eller ännu värre, fel under exekvering.