programmieren-3-c/a2-1
Luca Conte f063d1c519 a2-2 - a2-3 2023-10-11 15:53:01 +02:00
..
Makefile a2-2 - a2-3 2023-10-11 15:53:01 +02:00
README.md a2-2 - a2-3 2023-10-11 15:53:01 +02:00
differenz.c a2-1 a) 2023-10-04 13:52:29 +02:00
differenz.h a2-2 - a2-3 2023-10-11 15:53:01 +02:00
input.c a2-2 - a2-3 2023-10-11 15:53:01 +02:00
input.h a2-2 - a2-3 2023-10-11 15:53:01 +02:00
math.c a2-1 a) 2023-10-04 13:52:29 +02:00
projektname.h a2-2 - a2-3 2023-10-11 15:53:01 +02:00
summe.c a2-1 a) 2023-10-04 13:52:29 +02:00
summe.h a2-1 a) 2023-10-04 13:52:29 +02:00

README.md

A2-1 Ergebnisse

a)

input.c

Die input.c Datei enthält lediglich die get_input Funktion.

Wichtig ist, dass in der input.c Datei die stdio.h Header Datei eingebunden wird. Auch wenn diese Header Datei bereits durch die math.h Datei inkludiert wird, werden diese Dateien zunächst unabhängig voneinander in Objektcode umgewandelt, weshalb auch hier die Einbindung notwendig ist.

#include <stdio.h>

int get_input(char prompt[]) {
    printf("%s: ", prompt);
    int in;
    scanf("%d", &in);
    return in;
}

Des weiteren wird die input.h Datei benötigt, um von den differenz.c und summe.c Modulen eingebunden zu werden.

extern int get_input(char prompt[]);

summe.c und differenz.c

Der Aufbau der summe.c und der differenz.c Dateien ist überaus simpel, dank der Auslagerung der get_input Funktion in die input.c Datei.

Es müssen lediglich diese input.c Datei eingebunden werden, und anschließend zwei Integer eingelesen und addiert bzw. subtrahiert werden.

(Da sich die beiden Dateien sehr ähnlich sind, hier nur die summe.c Datei)

#include "input.h"

int summe(void) {
    int s1 = get_input("Erster Summand");
    int s2 = get_input("Zweiter Summand");
    return s1 + s2;
}

Da auch diese Dateien von der math.c Datei eingebunden werden müssen, sind wieder Header Dateien nötig

extern int summe(void);

math.c

In der math.c Datei müssen nun die zuvor geschriebenen summe.c und differenz.c Dateien eingebunden werden. Des weiteren wird auch die stdio Library benötigt, da hier nicht alle Ein- und Ausgaben von der input.c Datei übernommen werden können.

#include <stdio.h>
#include "differenz.h"
#include "summe.h"

void berechne(void) {
    printf("Ihre Wahl:\n");
    printf("<S>umme oder <D>ifferenz? ");
    char input;
    scanf("%c", &input);
    int ergebnis;
    if (input == 'S') {
        ergebnis = summe();
    } else if (input == 'D') {
        ergebnis = differenz();
    } else {
        printf("Ungueltige Eingabe\n");
        return;
    }
    printf("Ergebnis: %d\n", ergebnis);
    return;
}

int main(void) {
    berechne();
    return 0;
}

Die berechne(void) Funktion fragt lediglich eine Benutzereingabe ab und führt abhängig von dieser die summe() bzw differenz() Funktion aus und gibt das Ergebnis auf der Konsole aus. Für den Fall dass weder S noch D eingegeben wurden, wird eine Fehlemeldung ausgegeben und die Ausführung wird frühzeitig abgebrochen.

b)

Wird die get_input Funktion in der Header Datei implementiert, so entsteht folgende Fehlermeldung:

/tmp/cc0MAOBV.o: In function `get_input':
summe.c:(.text+0x0): multiple definition of `get_input'
/tmp/cciE9B24.o:differenz.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

Dieser Fehler entsteht beim Linken der Objektcode Dateien.

Begründung:

Beim Kompilierungsprozess wird zunächst der Präprozessor ausgeführt. Dieser wird hier keine Fehler zurückgeben, da alle Dateien Problemlos eingebunden werden Können. Die Definitionen innerhalb dieser Dateien sind hier noch nicht wirklich entscheident.

Anschließend werden die Dateien vom Kompilierer in Objektcode umgewandelt. Auch das sollte problemlos klappen, da die Dateien unabhängig voneinander kompiliert werden, und einzeln keine Fehler aufweisen.

Dass der Kompilierprozess erfolgreich war, lässt sich feststellen, indem man die -c Option mit angibt. Die .o Dateien werden alle problemlos erzeugt.

Nach dem Ausschlussverfahren lässt sich nun feststellen, dass die Fehlermeldung vom Linker erzeugt werden muss.

Dieses Verhalten ist auch zu erwarten, da erst beim zusammenfügen der Dateien die doppelte Definition der Funktion auffällt.

Des weiteren lässt sich auch in der Fehlermeldung bereits ablesen, dass der Linker nicht erfolgreich ausgeführt werden konnte.

collect2: error: ld returned 1 exit status

Hier wird angegeben, dass ld einen Fehlercode zurückgegeben hat (exit status nicht 0). Mit dem Befehl whatis lässt sich herrausfinden, dass es sich bei ld um den GNU linker handelt

$ whatis ld
ld (1)               - The GNU linker

c)

Damit die Definition der PROJEKT_NAME Konstante in jeder Header Datei verfügbar ist, kann man diese z.B. in eine eigene Datei auslagern:

projektname.h

#define PROJEKT_NAME "Tolles Projekt"

diese Datei kann man nun in den anderen Header Dateien includen

#include "projektname.h"

A2-3 Ergebnisse

Die ersten paar Zeilen der Makefile lassen sich "Kochrezept"-artig aus der Vorlesung übernehmen

GCC_ARGS = -std=c99 -pedantic-errors -Wall -Wstrict-prototypes

OBJ = math.o input.o summe.o differenz.o

math.out : $(OBJ)
    gcc $(GCC_ARGS) -o $@ $(OBJ)

%.o : %.c
    gcc $(GCC_ARGS) -c $<

Die OBJ Variable enthält die Namen aller benötigten Objektcode Dateien.

Das Target math.out muss ebenfalls angepasst werden. Der Rest ist jedoch allgemein gültig und Funktioniert dank den Pattern rules für viele C Programme.

Anschließend müssen die Abhängigkeiten angegeben werden. Diese funktionieren ergänzend zu der vorher definierten Pattern rule.

math.o : summe.h differenz.h

summe.o : input.h

differenz.o : input.h

Zuletzt wird noch ein simples clean Kommando definiert

clean:
    rm math.out $(OBJ)

Nun kann das Programm durch die Eingabe von make passend kompiliert werden

$ make
make
gcc -std=c99 -pedantic-errors -Wall -Wstrict-prototypes -c math.c
gcc -std=c99 -pedantic-errors -Wall -Wstrict-prototypes -c input.c
gcc -std=c99 -pedantic-errors -Wall -Wstrict-prototypes -c summe.c
gcc -std=c99 -pedantic-errors -Wall -Wstrict-prototypes -c differenz.c
gcc -std=c99 -pedantic-errors -Wall -Wstrict-prototypes -o math.out math.o input.o summe.o differenz.o

$ ./math.out
Ihre Wahl:
<S>umme oder <D>ifferenz?