Funktion aus anderer Datei aufrufen



  • Ich habe folgende Ordnerstruktur:
    calc
    -Makefile
    -src
    --calc.h
    --add.c
    --sub.c
    --mul.c
    --div.c
    --nop.c
    --power.c
    -bin
    -main
    --main.c

    In der main.c schreibe ich ein Kommandozeilenprogramm, dass auf die im src vorhandenen arithmetischen Operationen zugreifen soll. Man hat mir gesagt, ich könne die calc.h-Datei in meine main.c-Datei inkludieren, nun könne ich die Funktionen der anderen Dateien aufrufen, weil diese in der Header-Datei hinterlegt sind. Das geht aber nicht, hier der Code der main.c-Datei:

    #include <stdio.h>
     #include "../src/calc.h"
    
    int main(void) {
    
    	int choosed_operation = 0;
    	float argument1 = 0.0f;
    	float argument2 = 0.0f;
    	float result = 0.0f;
    	printf("Welcome! Please choose one operation (1-6):\n");
    	printf("1. Add 2. Sub 3. Mul 4. Div 5. Nop 6. Pow\n");
    	scanf("%d", &choosed_operation);
    	printf("Thanks, please enter two arguments, separated by a space:\n");
    	scanf("%f%f", &argument1, &argument2);
    
    	switch(choosed_operation) {
    		case 1:
    			result = add(argument1, argument2);
    			break;
    		case 2: 
    			result = sub(argument1, argument2);
    			break;
    		case 3: 
    			result = mul(argument1, argument2);
    			break;
    		case 4:
    			result = div(argument1, argument2);
    			break;
    		case 5:
    			result = nop(argument1, argument2);
    			break;
    		case 6:
    			result = power(argument1, argument2);
    			break;
    	}
    	printf("Result: %f", result);
    }
    

    Compiler meint undefinierte Referenz für jede einzelne Funktion.

    Wo liegt bitte mein Fehler?

    Zweite Frage: Ich möchte ein makefile für dieses Projektchen konzipieren. Meins sieht so aus:

    # calc/Makefile
    all: calculator
    calculator: add.o sub.o mul.o div.o nop.o power.o main.o
    		gcc -o calculator add.o sub.o mul.o div.o nop.o power.o main.o
    clean: 
    		rm .f *.o calculator
    
    add.o: add.c calc.h Makefile
    	gcc -c add.c
    sub.o: sub.c calc.h Makefile
    	gcc -c sub.c
    mul.o: mul.c calc.h Makefile
    	gcc -c mul.c
    div.o: div.c calc.h Makefile
    	gcc -c div.c
    nop.o: nop.c calc.h Makefile
    	gcc -c nop.o
    power.o: power.c calc.h Makefile
    	gcc -c power.o
    main.o: main.c calc.h Makefile
    	gcc -c main.o
    

    Kompiler meint: no rule to make target add.c, needed by add.o. Verstehe ich nicht.



  • user371 schrieb:

    Compiler meint undefinierte Referenz für jede einzelne Funktion.

    Wo liegt bitte mein Fehler?

    Das kommt nicht vom Compiler, sondern vom Linker. Dem Linker muss die main.o, die add.o usw. als Parameter bekommen um alle Funktionen zu finden.

    user371 schrieb:

    Kompiler meint: no rule to make target add.c, needed by add.o. Verstehe ich nicht.

    Das kommt auch nicht vom Compiler, sondern von Make. Die Dateien die du als Abhängigkeiten angibst muss Make auch finden können. Make sucht nicht automatisch in Unterordnern, du musst schon die Pfade richtig angeben bzw. dafür sorgen das die durchsucht werden.

    Außerdem ist der gcc Aufruf unvollständig. Wo sind die Eingabefiles?



  • Zunächst danke für deine Antwort.

    Tobiking2 schrieb:

    Das kommt nicht vom Compiler, sondern vom Linker. Dem Linker muss die main.o, die add.o usw. als Parameter bekommen um alle Funktionen zu finden.

    Es genügt also nicht, dass ich die Funktionsdeklarationen im Header-File angebe, welches in main.c inkludiert wird?

    Tobiking2 schrieb:

    Das kommt auch nicht vom Compiler, sondern von Make. Die Dateien die du als Abhängigkeiten angibst muss Make auch finden können. Make sucht nicht automatisch in Unterordnern, du musst schon die Pfade richtig angeben bzw. dafür sorgen das die durchsucht werden.
    Außerdem ist der gcc Aufruf unvollständig. Wo sind die Eingabefiles?

    # calc/Makefile
    all: calculator
    calculator: /src/add.o /src/sub.o /src/mul.o /src/div.o /src/nop.o /src/power.o /main/main.o
    		gcc -o calculator /src/add.o /src/sub.o /src/mul.o /src/div.o /src/nop.o /src/power.o /main/main.o
    clean: 
    		rm .f *.o calculator
    
    add.o: /src/add.c /src/calc.h Makefile
    	gcc -c /src/add.c
    sub.o: /src/sub.c /src/calc.h Makefile
    	gcc -c /src/sub.c
    mul.o: /src/mul.c /src/calc.h Makefile
    	gcc -c /src/mul.c
    div.o: /src/div.c /src/calc.h Makefile
    	gcc -c /src/div.c
    nop.o: /src/nop.c /src/calc.h Makefile
    	gcc -c /src/nop.c
    power.o: /src/power.c /src/calc.h Makefile
    	gcc -c /src/power.c
    main.o: /main/main.c /main/calc.h Makefile
    	gcc -c /main/main.c
    

    So ungefähr?

    Und was meinst du bitte mit gcc-Aufruf?



  • Es ist folgendermaßen: Der Compiler (cc) übersetzt jede Datei einzeln, und zwar in eine Objektdatei. Das heißt für ein erfolgreiches Kompilieren müssen die Funktionsprototypen bekannt sein (Beachte: Nicht zwingend der Funktionscode selbst, wenn man z.b. gegen externe Bibliotheken linkt).
    Und genau dafür sind eben die Headerfiles gut.
    Aber deine Projektstruktur ist absolut ungeeignet, weil make mit Hierarchien nicht so ganz trivial ist. Nimm einfach die main.c mit in das src/ Vereichnis.
    Und schaue dir bitte einmal Platzhalter und Make Variablen an. Dann wird das Makefile viel übersichtlicher.
    Der gcc Aufruf ist vollständig, keine Sorge. Aufruf meint einfach die Zeile(n) im Makefile wo gcc eben aufgerufen wird.

    Aber jetzt mal dazu das ganze zum Laufen zu bekommen: /src/*.c ist ein absoluter Pfad, da wirst du nichts finden. Mach einfach eine ganz flache Struktur. Ein Ordner mit Quellcode, Objectdateien, den Headern, dem Makefile und dem Binary und dann sollte es passen.



  • Es genügt also nicht, dass ich die Funktionsdeklarationen im Header-File angebe, welches in main.c inkludiert wird?

    Nein. Einerseits brauchst du die #include "sowienoch.c" für den Compiler, daneben musst du aber auch dem Linker sagen welche Objektdateien (.o) er verwursten soll.

    Erinnerung: Der Compiler verarbeitet jede C-Datei einzelnd zu einer .o-Datei. Der Linker setzt die .o-Dateien zu einer fertigen ausführbaren Datei zusammen.

    Von Makefiles verstehe ich nichts.



  • Vielen Dank für die Erklärung! Problem ist, dass ich diese Ordnerstruktur beibehalten muss, ist ein Teil einer Studiums-Aufgabe.

    Das Makefile muss quasi im "Stammverzeichnis" sein, das main.c-File im main-Ordner und alle benötigten Funktionalitäten im src-Ordner.



  • Tobiking2 schrieb:

    Das kommt nicht vom Compiler, sondern vom Linker. Dem Linker muss die main.o, die add.o usw. als Parameter bekommen um alle Funktionen zu finden.

    Wie übergebe ich dem Linker die Parameter?



  • Ok, ich bin weitergekommen. Etwas aber verstehe ich nicht.

    So funktioniert das Makefile und mein Projekt:

    # calc/Makefile
    
    CC := gcc
    CFLAGS += -std=c99
    CFLAGS += -Wall
    CFLAGS += -Wextra
    CFLAGS += -g
    
    VPATH = main src
    
    all: clean bin/main.exe clean run
    # (1)
    bin/main.exe: bin/main.o bin/add.o bin/sub.o bin/mul.o bin/dif.o bin/nop.o bin/power.o
    	$(CC) -o $@ $^
    #	gcc -o bin/make.exe bin/main.o /bin/add.o /bin/sub.o /bin/mul.o /bin/dif.o /bin/nop.o /bin/power.o
    bin/main.o: main.c
    
    	$(CC) $(CFLAGS) -c -o $@ $^
    bin/add.o: add.c 
    	$(CC) $(CFLAGS) -c -o $@ $^
    bin/sub.o: sub.c 
    	$(CC) $(CFLAGS) -c -o $@ $^
    bin/mul.o: mul.c 
    	$(CC) $(CFLAGS) -c -o $@ $^
    bin/dif.o: dif.c
    	$(CC) $(CFLAGS) -c -o $@ $^
    bin/nop.o: nop.c 
    	$(CC) $(CFLAGS) -c -o $@ $^
    bin/power.o: power.c
    	$(CC) $(CFLAGS) -c -o $@ $^
    
    clean: 
    	rm -f bin/*.o 
    run:
    	bin/main.exe
    

    Aber wenn ich beim Target bin/main.exe die auskommentierte Version nehme statt diejenige mit den Variablen, dann gehts nicht.
    Ich erhalte dann seitens Make bei der Auführung der bin/main.exe-Kommando den Fehler, dass es unter bin/ keine solchen Objektfiles gäbe. Obwohl ich sie selber in der Ordnerstruktur dort sehe!

    Wieso ist das bitte so?
    An den Optionen, die ich als CFLAGS definiert habe, kann es nicht liegen, denn wenn ich sie alle ausklammere, funktioniert es immer noch.

    Ähnliche Frage bei den einzelnen Target-Objektfiles: Dort kann ich nicht statt den jetzt verwendeten Variablen das hier nehmen:

    gcc -c main.c
    

    Wenn ich das tue, dann werden die daraus generierten Objektfiles nämlich nicht in /bin abgelegt, sondern auf der Ebene des Makefiles.



  • user371 schrieb:

    Ich erhalte dann seitens Make bei der Auführung der bin/main.exe-Kommando den Fehler, dass es unter bin/ keine solchen Objektfiles gäbe. Obwohl ich sie selber in der Ordnerstruktur dort sehe!

    Wieso ist das bitte so?

    Du verwendest immernoch absolute Pfade.



  • SG1 schrieb:

    Du verwendest immernoch absolute Pfade.

    Mmh, sorry, das war ganz dumm von mir. 😑
    Danke! Das zweite Problem bleibt jetzt noch offen. Kann da bitte jemand helfen?


Log in to reply