PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C: Call to function xy with no prototype


mf_2
2004-02-21, 18:05:05
Hallo,

Ich habe ein Problem.

Ich hab eine c-Datei core.c. Diese ruft ein paar selbstgeschriebene Funktionen ( z.b. testfunktion() ) aus anderen Datein auf. Eine dieser anderen Dateien heisst funktionen.c
In core.c habe ich unter anderem am Anfang
"#include <funktionen.h>"
eingegeben.

Der Inhalt von funktionen.h ist eigentlich nur folgender:

int testfunktion();


die eigentliche funktion kommt dann in der funktionen.c
Nun bekomme ich aber immer u.a. diese Warnung in core.c beim Compilieren:
Call to function 'testfunktion' with no prototype.
Ich denke ich habe in der h-Datei Mist gebaut, da die Funktion an sich ja funktioniert, es ist ja kein Fehler, "nur" ne Warnung. Aber trotzdem wäre es gut, immer alle Warnungen zu beseitigen.

P.S.:
Noch eine Frage:
Ich habe unegfähr folgende Datei:

#include <stdio.h>

int main()
{

eins();
zwei();

return 0;
}

int eins()
{

printf("Hallo!\n");

return 0;

}

int zwei()
{

printf("Auf Wiedersehen");

return 0;

}


Dann bekomme ich folgenden Linker-Fehler:
Undefined symbol __zwei referenced from C:\programme\borland\cbuilder\projects\core.obj
Woran liegt das? Der Aufruf von eins() geht problemlos, der von zwei() aber nicht.

Hoffentlich könnt ihr mir helfen., ich verzweifle hier noch.
Ich hab auch schon zu beiden Problemen gegoogelt, finde aber nichts nützliches.

Lord Nikon
2004-02-21, 18:46:17
ich nehm mal an das du mit dem c++ Builder arbeitest.
Geh auf den Projekt/ Dem Projekt hinzufügen und wählst die entsprechende cpp Datei aus , dannach sollte der obj Fehler weg gehen.

mf_2
2004-02-21, 19:06:25
Nee, es sind noch beide Fehler da ( die Warnung und der Fehler ). Ausserdem ist es eine c- und keine cpp-Datei, aber das ist egal, oder?

Gast
2004-02-21, 22:58:17
Wenn du C verwendest (nicht C++) dann musst du den Prototyp anders schreiben:

int testfunktion(void);

Das void kann man dann bei der Defintion weglassen, aber bei der Deklaration ist das () eben kein Prototyp, weil die Parameterliste fehlt.
In C++ ist die Bedeutung anders. Da dort Prototypen vorgeschrieben sind, macht das Weglassen der Parameter keinen Sinn.

mf_2
2004-02-21, 23:23:25
alwso ich hab jetzz in der funktionen.h einfach ein void in die klammern geschrieben, geht aber immer noch ned.
etwas ist mir auch noch aufgefallen:
wenn ich in funktion.c eine andere funktion aus funktion.c aufrufen will, bekomm ich die gleiche warnung. obwohl beides in der selben datei steht. das verwirrt irgendwie...

Xmas
2004-02-22, 03:58:04
Die Reihenfolge von Deklaration und Aufruf ist relevant. Die Deklaration muss vor dem Aufruf stehen.

Falsch:
int main() {
flubb();
return 0;
}

void flubb() {
printf("flabb");
}

Richtig:
void flubb() {
printf("flabb");
}

int main() {
flubb();
return 0;
}

oder:
void flubb(void);

int main() {
flubb();
return 0;
}

void flubb() {
printf("flabb");
}

Xmas
2004-02-22, 04:08:48
Original geschrieben von Gast
Wenn du C verwendest (nicht C++) dann musst du den Prototyp anders schreiben:

int testfunktion(void);

Das void kann man dann bei der Defintion weglassen, aber bei der Deklaration ist das () eben kein Prototyp, weil die Parameterliste fehlt.
In C++ ist die Bedeutung anders. Da dort Prototypen vorgeschrieben sind, macht das Weglassen der Parameter keinen Sinn.
Das stimmt so nicht. In ANSI-C bedeutet int bla(); , dass kein Type Checking gemacht werden soll, während int bla(void); heißt, dass keine Argumente erlaubt sind. In C++ ist beides äquivalent dem letzten.

Gast
2004-02-22, 07:42:37
Original geschrieben von Gast

Wenn du C verwendest (nicht C++) dann musst du den Prototyp anders schreiben:

int testfunktion(void);

Das void kann man dann bei der Defintion weglassen, aber bei der Deklaration ist das () eben kein Prototyp, weil die Parameterliste fehlt.
In C++ ist die Bedeutung anders. Da dort Prototypen vorgeschrieben sind, macht das Weglassen der Parameter keinen Sinn.
Original geschrieben von Xmas
Das stimmt so nicht. In ANSI-C bedeutet int bla(); , dass kein Type Checking gemacht werden soll, während int bla(void); heißt, dass keine Argumente erlaubt sind. In C++ ist beides äquivalent dem letzten.

Das stimmt zwar, aber ich sehe nicht ganz was an meinem Posting falsch gewesen wäre? Also nochmal anders ausgedrückt:


// ISO C
int bla(); // Deklaration einer Funktion mit Typ int (kein Prototyp, weil keine Parameterliste)
int bla(void); // Prototyp
// C++
int bla(); // Prototyp

In C++ könnte man mit dem C-bla() nicht viel anfangen, weil durch das Overloading nicht nur der Funktionsname sondern auch die Typen der Parameter die Funktion identifizieren. Dazu muss der Compiler beim Aufruf der Funktion entweder den Prototypen oder die Definition selber gesehen hat.


int bla(int n = 0); // Prototyp mit Default Parameter

int main()
{
bla(); // Ohne den Prototyp könnte der Compiler nur bla(void) oder extern "C" schätzen. Beides falsch.
bla('a'); // bla(int) wird aufgerufen, da bla(char) nicht existiert. Dank Prototyp ist kein Cast nötig
}

govou
2004-02-22, 12:56:22
mf_2: mach doch ein extra "mf_2 C Thread" auf...

mf_2
2004-02-22, 13:21:47
Es klappt immer noch nicht. Vielleicht bin ich auch einfach zu blöd dafür. Was ist denn genau der Unterschied zwischen Deklaration, Prototyp und Definition?

Gast
2004-02-22, 19:48:48
Original geschrieben von mf_2
Es klappt immer noch nicht. Vielleicht bin ich auch einfach zu blöd dafür. Was ist denn genau der Unterschied zwischen Deklaration, Prototyp und Definition?

Der genaue Unterschied würde dir nicht weiterhelfen (kannst ihn aber zur Not mit Google rausfinden). Es ist nur wichtig, dass du das void nicht vergisst (solange du in C und nicht C++ programmierst). Benutze int f(); am besten niemals, sondern immer int f(void);. Jedenfalls solange du nicht doch lieber C++-only programmieren möchtest.

Einem Prototypen fehlt einfach der Funktions-Body. Aber es ist alles vorhanden, was der Compiler wissen muss, um die Funktion aufzurufen. Der Body der Funktion (welcher Teil der Definition ist) kann dann z.B. irgendwann später im Programm-Text stehen. Oder der Code steht in einem anderen Modul deines Programms oder einer Bibliothek.


Du musst die Reihenfolge beachten wie Xmas es dir erklärt hat. Damit sollte alles klappen. Denke daran, dass der Compiler nur ein einziges Programm-Modul am Stück compiliert. Header-Dateien werde mittels Präprozessor-Anweisung einfach als Text in das Programm eingefügt. Und zwar genau dort wo das #include steht. Du kannst also anstelle des #include <funktionen.h> auch einfach den Inhalt der Datei funktionen.h in die C-Datei pasten. Das wäre dann das, was der Compiler im Endeffekt zu sehen bekommt.

Du solltest übrigens schreiben:
#include "funktionen.h"

Also mit "" statt <>. Letzteres ist für Header gedacht, welche nicht im aktuellen Verzeichnis sind sondern im include-Suchpfad.

Wenn du nicht weiterkommst, kannst du einfach mal aus deiner C Datei eine C++ Datei machen. Ein C++ Compiler erzeugt oft bessere Fehlermeldungen (besonders der gcc). Später kannst du dann ja wieder C draus machen.


Ausserdem solltest du alle Funktionen welche nicht ausserhalb des Moduls benutzt werden als static deklarieren.
Diese werden dann nicht mehr gelinkt und du bekommst keine Linker-Fehler sondern direkt Fehlermeldungen vom Compiler, welche oft besser verständlich sind.


int globale_funktion(void); // sollte am besten in einem Headerstehen

static int modul_funktion(void);

int globale_funktion(void)
{
return modul_funktion();
}

static int modul_funktion(void)
{
return 42;
}

Gast
2004-02-22, 20:37:12
Und umgekehrt solltest du natürlich alle anderen Funkionen nicht als static deklarieren bzw. definieren.

Ansonsten käme genauso eine Fehlermeldung wie du sie hattest. Die Fehlermeldung bedeutet, dass der Compiler für den Aufruf der Funktion einen Assembler-Code erzeugt hat, welcher das Label-Symbol __zwei anspringt. An anderer Stelle hat er die Funktion zwei() nach Assembler-Code compiliert und den Eingang der Funktion mit dem Label __zwei markiert.

Der Linker vermisst bei deiner Fehlermeldung nun offenbar das Label __zwei. Mögliche Ursachen dabei wären:
- Schreibfehler bei der Funktions-Definition (Zwei() oder zwie())
- Funktion wurde als static definiert (dadurch nicht ausserhalb des Moduls sichtbar)
- Das Modul welches die Funktion enthält wurde nicht mit gelinkt (also die .obj Datei wird zwar compiliert, aber nicht dem Linker übergeben).
- Mixen von C++ und C. C++ Funktionen benutzen andere Symbole zum Linken. Damit ein C Modul eine Funktion aus einem C++ Modul aufrufen kann, muss diese im C++ Modul als extern "C" deklariert werden. Tut man das nicht, hat man dann Symbole in der Art von __zwei beim Aufruf und __zwei$VOID (jedenfalls in der Art) bei der Definition.