Forum: PC-Programmierung Spass mit Prototypen in C


von Dergute W. (derguteweka)


Lesenswert?

Moin,

Grad' bin ich in eine lustige Fallgrube gestolpert - da lass ich doch 
gerne die Experten sich dran ergoetzen:
Folgende Dateien
main.c:
1
/* compile with:
2
 gcc -I. -Wall -Wextra -pedantic bla.c main.c 
3
*/
4
5
#include<bla.h>
6
7
int main() {
8
    return bla();
9
}

bla.c:
1
#include <stdio.h>
2
#include <bla.h>
3
4
int bla(int * blupp) {
5
    printf("will access %p\n",(void*)blupp);
6
    fflush(stdout);
7
    *blupp = 42;
8
    return 0;
9
}

bla.h:
1
int bla();

kompilieren ohne jeden Mecker zu einem executable, was dann dank nicht 
zusammenpassender Funktion/Prototyp in bla.c und bla.h irgendwo in den 
Speicher schreibt.
Wasnichtallesschiefgehenkann...

Gruss
WK

von Mike (Gast)


Lesenswert?

>kompilieren ohne jeden Mecker

Wirklich? Mit welchem Compiler?

MIS(T)RA-C Rule No 42:
-If you get too many compile-warnigs, adjust your warning level 
settings!

von DPA (Gast)


Lesenswert?

Dergute W. schrieb:
> int bla();


Naja, das ist halt so, wenn man "int bla();" statt "int bla(void);" 
schreibt.
Das "int bla();" hat schon seinen Verwendungszweck, ist aber hier fehl 
am platz.

Ich würde beim Compilieren ausserdem noch "-std=c99" oder "-std=c11" 
hinzufügen, sonst weiss man nie so genau, welche Programmiersprache das 
jetzt wieder sein soll.

von Udo K. (Gast)


Lesenswert?

garbage in - garbage out

von Ste N. (steno)


Lesenswert?

DPA schrieb:
> Das "int bla();" hat schon seinen Verwendungszweck, ist aber hier fehl
> am platz.

Das würde mich jetzt aber mal interessieren. Bin ja immer noch am dazu 
lernen. Welcher Verwendungszweck wäre das genau?

Das im obigen Beispiel der Compiler keinen Fehler auswirft, wundert mich 
allerdings schon.

von mh (Gast)


Lesenswert?

Ste N. schrieb:
> Das im obigen Beispiel der Compiler keinen Fehler auswirft, wundert mich
> allerdings schon.

Der Compiler kann nicht warnen, da er nur
1
int bla();
2
int main() {
3
    return bla();
4
}
sieht.

von Hans (Gast)


Lesenswert?

naja c compiler nehmen es mit den prototypen (und pointer typen!) nicht 
soo genau...

ich hätte mir da aber auch eine warning erhofft...


der c++ compiler sieht es jedenfalls nicht so lax:

bash-4.3$  gcc -x c++  -I. -Wall -Wextra -pedantic  bla.c main.c
/tmp/ccTUJjgt.o: In function `main':
main.c:(.text+0x5): undefined reference to `bla()'
collect2: error: ld returned 1 exit status


damit ist meine welt wieder in ordnung :)

73

von (prx) A. K. (prx)


Lesenswert?

Ste N. schrieb:
> Das würde mich jetzt aber mal interessieren. Bin ja immer noch am dazu
> lernen. Welcher Verwendungszweck wäre das genau?

Code ohne Prototypes. Die gibt es erst seit C89. Die Deklaration "int 
bla();" ist nicht etwa eine Funktion ohne Parameter, sondern lässt die 
Frage nach den Parametern völlig offen.
1
> gcc -c -Wmissing-prototypes test.c
2
4.c:3:5: warning: no previous prototype for ‘bla’ [-Wmissing-prototypes]
3
 int bla(int blubb)
4
     ^

Hans schrieb:
> damit ist meine welt wieder in ordnung :)

C++ ist in dieser Frage anders als C.

: Bearbeitet durch User
Beitrag #5649682 wurde vom Autor gelöscht.
von Bernd K. (prof7bit)


Lesenswert?

Dergute W. schrieb:
> kompilieren ohne jeden Mecker zu einem executable

Ja, der Compiler nimmt an daß Du Code aus der Ära von Kerninghan oder 
Ritchie schreibst. Mit Spaß hat das nichts zu tun, Prototypen ohne 
Argumentliste war gültige Syntax.

Man kann dem Compiler mitteilen daß er meckern soll, zum Beispiel mit 
-Wstrict-prototypes. (leider nicht in -Wall und -Wextra enthalten um die 
Kompatibilität mit altem Code zu wahren)

von (prx) A. K. (prx)


Lesenswert?

mh schrieb:
> Der Compiler kann nicht warnen,

Wenn er bla.c übersetzt, sieht er beides. Da warnt er, wenn man ihn 
lässt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

1
$ cat func.c
1
#include <stdio.h>
2
3
int func();
4
5
int func(int param)
6
{
7
    return param;
8
}
9
10
int main()
11
{
12
    int foo = func(10);
13
    printf("%d", foo);
14
    return 0;
15
}
1
$ cc -Wall -Wextra -pedantic func.c
2
$ cc -Wall -Wextra -pedantic -Wstrict-prototypes func.c
3
func.c:3:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]

Also: Option -Wstrict-prototypes immer mit angeben.

: Bearbeitet durch Moderator
von Ste N. (steno)


Lesenswert?

Dank mc.net wieder was gelernt... Ich danke euch!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Also: Option -Wstrict-prototypes immer mit angeben.

Und/oder sich einfach angewöhnen, nie eine Deklaration foo() zu 
schreiben, sondern immer foo(void).  In C++ wäre zwar (anders als in 
C) beides dasselbe, aber es ist eben auch dort nicht verboten, das 
„void“ explizit zu schreiben.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> Und/oder sich einfach angewöhnen, nie eine Deklaration foo() zu
> schreiben, sondern immer foo(void).

Ich muss zugeben, dass ich das void in einer Deklaration ab und zu 
einfach vergesse. Das kommt zwar selten vor, fällt aber dank 
-Wstrict-prototypes sofort auf.

von MaWin (Gast)


Lesenswert?

Hans schrieb:
> undefined reference to `bla()'
>
> damit ist meine welt wieder in ordnung :)

Das ist jetzt aber auch eine extem blöde Fehlermeldung, die Anfängern in 
diesem einfachen Fall und auch Erfahreneren in komplexeren Fällen in die 
Irre führt.

Natürlich gibt es bla, nur halt in der Form bla(int *) statt bla(). Ein 
bischen mehr Gehirnschmalz könnte gcc da schon einsetzen, bzw. seine 
Erbauer.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

MaWin schrieb:
> Ein bischen mehr Gehirnschmalz könnte gcc da schon einsetzen, bzw. seine
> Erbauer.

Ist halt nicht GCC, sondern der Linker.

von Yalu X. (yalu) (Moderator)


Lesenswert?

MaWin schrieb:
> Hans schrieb:
>> undefined reference to `bla()'
>>
>> damit ist meine welt wieder in ordnung :)
>
> Das ist jetzt aber auch eine extem blöde Fehlermeldung

Naja, wenn der Programmierer gleich an zwei Stellen sagt, er möchte eine
Funktion bla ohne Argumente, nämlich sowohl

- im Protoyp als auch
- im Aufruf,

glauben ihm Compiler und Linker das und gehen davon aus, dass einfach
nur vergessen wurde, die Funktion zu implementieren bzw. dem Linker das
entsprechende Modul oder die Bibliothek bekannt zu geben.

Nur wenn Aufruf und Prototyp(en) überhaupt nicht zusammenpassen, zeigt
dies der Compiler an und listet bei überladenen Funktionen die möglichen
Kandidaten auf.

von Rolf M. (rmagnus)


Lesenswert?

A. K. schrieb:
> Ste N. schrieb:
>> Das würde mich jetzt aber mal interessieren. Bin ja immer noch am dazu
>> lernen. Welcher Verwendungszweck wäre das genau?
>
> Code ohne Prototypes. Die gibt es erst seit C89. Die Deklaration "int
> bla();" ist nicht etwa eine Funktion ohne Parameter, sondern lässt die
> Frage nach den Parametern völlig offen.

Aber wozu braucht man das heute noch? In C++ wurde es abgechafft, und in 
C ist es meiner Meinung nach nur drin, um alten Code nicht inkompatibel 
zu machen.

>> gcc -c -Wmissing-prototypes test.c
> 4.c:3:5: warning: no previous prototype for ‘bla’ [-Wmissing-prototypes]
>  int bla(int blubb)
>      ^

Ich nehme da gleich -Werror=missing-prototypes. Dann ist es wie in C++.

A. K. schrieb:
> mh schrieb:
>> Der Compiler kann nicht warnen,
>
> Wenn er bla.c übersetzt, sieht er beides. Da warnt er, wenn man ihn
> lässt.

Da ist aber formal nichts falsch dran.

MaWin schrieb:
> Hans schrieb:
>> undefined reference to `bla()'
>>
>> damit ist meine welt wieder in ordnung :)
>
> Das ist jetzt aber auch eine extem blöde Fehlermeldung, die Anfängern in
> diesem einfachen Fall und auch Erfahreneren in komplexeren Fällen in die
> Irre führt.

Es ist allerdings auch eine unglückliche Situation.

> Natürlich gibt es bla, nur halt in der Form bla(int *) statt bla().

der Programmierer hat dem Compiler gesagt: Es gibt eine Funktion bla(), 
die irgendwo anders implementiert ist. Sie ist aber nirgends anders 
implementiert. bla(int*) ist zunächst mal eine andere Funktion. So kann 
dann erst der Linker erkennen, dass die gewünschte Funktion gar nicht 
existiert.

von mh (Gast)


Lesenswert?

Rolf M. schrieb:
> A. K. schrieb:
>> mh schrieb:
>>> Der Compiler kann nicht warnen,
>>
>> Wenn er bla.c übersetzt, sieht er beides. Da warnt er, wenn man ihn
>> lässt.
>
> Da ist aber formal nichts falsch dran.

Deswegen auch eine Warnung. Ich habe lange überlegt, ob mir ein Beispiel 
einfällt, bei dem die Warnung nicht gerechtfertigt ist und mich stören 
würde. Mir ist allerdings keins eingefallen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Aber wozu braucht man das heute noch?

Insbesondere ist natürlich die Frage, warum die Warnung nicht 
standardmäßig an ist.

> In C++ wurde es abgechafft,

Die hatten es einfacher: dort gab es das nie.

von Carl D. (jcw2)


Lesenswert?

Jörg W. schrieb:
> Frank M. schrieb:
>> Also: Option -Wstrict-prototypes immer mit angeben.
>
> Und/oder sich einfach angewöhnen, nie eine Deklaration foo() zu
> schreiben, sondern immer foo(void).  In C++ wäre zwar (anders als in
> C) beides dasselbe, aber es ist eben auch dort nicht verboten, das
> „void“ explizit zu schreiben.

In C++ haben aber die Funktionen foo() und foo(int) intern nicht den 
gleichen Namen. Das hilft dem Linker ungemein.

von MaWin (Gast)


Lesenswert?

Yalu X. schrieb:
> Naja, wenn der Programmierer gleich an zwei Stellen sagt, er möchte eine
> Funktion bla ohne Argumente

Sagt er nicht. In der Deklaration steht nicht void. Er sagt also nur, 
dass er über die Parameter nichts aussagen will.

Rolf M. schrieb:
> der Programmierer hat dem Compiler gesagt: Es gibt eine Funktion bla(),
> die irgendwo anders implementiert ist. Sie ist aber nirgends anders
> implementiert. bla(int*) ist zunächst mal eine andere Funktion. So kann
> dann erst der Linker erkennen, dass die gewünschte Funktion gar nicht
> existiert

Diese Meinung vertreten nur die Computernerds, die kein Gehirn für die 
wirkliche Welt mehr übrig haben. Die begründen dann durch Erklärung der 
internen Mechanismen, warum sich der Computer so doof verhält, dass der 
Anwender sich die Haare rauft. An statt das Verhalten des Computers 
durch geeignete interne Strukturierung an die Erwartungshaltung der 
Anwender anzupassen.

von (prx) A. K. (prx)


Lesenswert?

mh schrieb:
> Deswegen auch eine Warnung. Ich habe lange überlegt, ob mir ein Beispiel
> einfällt, bei dem die Warnung nicht gerechtfertigt ist und mich stören
> würde. Mir ist allerdings keins eingefallen.

Ich habe wahrscheinlich noch Code aus den 80ern auf Disk. Allerdings 
halte ich es es für zumutbar, eventuelle Makefiles ggf so zu tunen, dass 
ein heutiger Compiler damit zurecht kommt. Zumal solcher Code ggf auch 
noch gegen die integer conversion rules von ANSI-C verstösst.

von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> Rolf M. schrieb:
>> der Programmierer hat dem Compiler gesagt: Es gibt eine Funktion bla(),
>> die irgendwo anders implementiert ist. Sie ist aber nirgends anders
>> implementiert. bla(int*) ist zunächst mal eine andere Funktion. So kann
>> dann erst der Linker erkennen, dass die gewünschte Funktion gar nicht
>> existiert
>
> Diese Meinung vertreten nur die Computernerds, die kein Gehirn für die
> wirkliche Welt mehr übrig haben. Die begründen dann durch Erklärung der
> internen Mechanismen, warum sich der Computer so doof verhält, dass der
> Anwender sich die Haare rauft.

Ja, ich weiß, dass viele Leute in der "wirklichen Welt" der technische 
Grund, warum etwas nicht so funktioniert, wie sie es gerne hätten, nicht 
interessiert. Die wollen halt, dass die "Computernerds" ihnen ihre 
Probleme lösen und ansonsten die Klappe halten.

> An statt das Verhalten des Computers durch geeignete interne
> Strukturierung an die Erwartungshaltung der Anwender anzupassen.

Man sollte also die komplette grundlegende Struktur, wie Compiler und 
Linker zusammen arbeiten, über den Haufen werfen, damit eine 
anfängerfreundlichere Warnung ausgegeben wird?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Man sollte also die komplette grundlegende Struktur, wie Compiler und
> Linker zusammen arbeiten, über den Haufen werfen, damit eine
> anfängerfreundlichere Warnung ausgegeben wird?

Muss man nicht. Der Compiler macht ja bei Fehlermeldungen mittlerweile 
auch solche Heuristiken ("candidates are …"), das könnte durchaus auch 
der Linker tun. Hat sich offenbar nur noch niemand gemüßigt gefühlt.

Hat natürlich auf der anderen Seite auch den Effekt, dass einem der 
Linker plötzlich 30 Kandidaten um die Ohren werfen könnte, die alle 
"irgendwie passen könnten". Ist die Frage, ob damit dem Anwender dann 
wirklich mehr geholfen wäre.

von Yalu X. (yalu) (Moderator)


Lesenswert?

MaWin schrieb:
> Yalu X. schrieb:
>> Naja, wenn der Programmierer gleich an zwei Stellen sagt, er möchte eine
>> Funktion bla ohne Argumente
>
> Sagt er nicht. In der Deklaration steht nicht void. Er sagt also nur,
> dass er über die Parameter nichts aussagen will.

Es ging in der Aussage von Hans, auf die du dich bezogst, nicht um C,
sondern um C++. Hier noch einmal die Historie in der Übersicht:

Hans schrieb:
> der c++ compiler sieht es jedenfalls nicht so lax:
>
> bash-4.3$  gcc -x c++  -I. -Wall -Wextra -pedantic  bla.c main.c
> /tmp/ccTUJjgt.o: In function `main':
> main.c:(.text+0x5): undefined reference to `bla()'

MaWin schrieb:
> Das ist jetzt aber auch eine extem blöde Fehlermeldung

Yalu X. schrieb:
> Naja, wenn der Programmierer gleich an zwei Stellen sagt, er möchte eine
> Funktion bla ohne Argumente, ...

von MaWin (Gast)


Lesenswert?

Rolf M. schrieb:
> Man sollte also die komplette grundlegende Struktur, wie Compiler und
> Linker zusammen arbeiten, über den Haufen werfen

Nein man muss nicht, auch nach Typemangling stehen die Funktionsnamen 
noch drin und man kann gleichlautende erkennen. Man muss nur ein paar 
weitere Codezeilen schreiben, also seine Faulheit überwinden, "Wieso 
ändern, kommt doch irgendeine Meldung,  ich mach jetzt Feierabend und 
geh zocken"

> damit eine
> anfängerfreundlichere Warnung ausgegeben wird?

Damit eine sinnvolle Meldung ausgegeben wird.
Microsoft hat bei seinem Compiler auch gelernt. Noch nicht perfekt, aber 
viel besser als früher.

von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> Rolf M. schrieb:
>> Man sollte also die komplette grundlegende Struktur, wie Compiler und
>> Linker zusammen arbeiten, über den Haufen werfen
>
> Nein man muss nicht, auch nach Typemangling stehen die Funktionsnamen
> noch drin und man kann gleichlautende erkennen. Man muss nur ein paar
> weitere Codezeilen schreiben, also seine Faulheit überwinden,

Dann tu das doch einfach. Die Binutils-Entwickler freuen sich sicher 
über einen Patch.

>> damit eine anfängerfreundlichere Warnung ausgegeben wird?
>
> Damit eine sinnvolle Meldung ausgegeben wird.
> Microsoft hat bei seinem Compiler auch gelernt. Noch nicht perfekt, aber
> viel besser als früher.

Dafür haben sie sie sich bei allem anderem im Bezug auf die 
Fehlermeldungen noch weiter verschlechtert. Aber das ist ein genereller 
Trend, nicht nur bei Microsoft. Früher kam wenigstens noch ein bisschen 
Information, heute kann man froh sein, wenn überhaupt noch eine Meldung 
kommt, in der dann sowas hilfreiches steht wie "Huch, etwas ist schief 
gelaufen", wahlweise mit dem Vorschlag, sich an den Administrator zu 
wenden oder es später nochmal zu versuchen.

von Bernd K. (prof7bit)


Lesenswert?

Rolf M. schrieb:
> Aber das ist ein genereller
> Trend, nicht nur bei Microsoft. Früher kam wenigstens noch ein bisschen
> Information,

Das liegt daran daß heute im Gegensatz zu früher 99% der 
Computerbenutzer Normalsterbliche sind die erwarten daß es 
funktioniert[TM] wie eine Kaffeemaschine oder ein elektrischer 
Dosenöffner ohne auch nur im Geringsten an irgendwelchen Details der 
genauen Abläufe interessiert zu sein. Es gibt für diesen Personenkreis 
nur zwei Zustände: "funktioniert" und "funktioniert nicht", weder das 
"wie" noch das "warum" spielen für die irgendeine Rolle.

Das eine Prozent die das anders sehen (und aus dem sich in der guten 
alten Pionierzeit[TM] 100% der Computernutzer rekrutiert haben) weichen 
heute auf Linux aus weil sie die zunehmende Verdummung und Entmündigung 
des Anwenders nicht mehr ertragen können.

von mh (Gast)


Lesenswert?

Bernd K. schrieb:
> Das liegt daran daß heute im Gegensatz zu früher 99% der
> Computerbenutzer Normalsterbliche sind die erwarten daß es
> funktioniert[TM] wi

Glaubst du wirklich, dass diese Personen einen C-Compiler benutzen? Und 
wenn ja, benutzen die den gcc?

von Bernd K. (prof7bit)


Lesenswert?

mh schrieb:
> Glaubst du wirklich, dass diese Personen einen C-Compiler benutzen?

Ich bezog mich darauf daß mein Vorposter sich darauf bezog daß ein 
genereller Trend bei Fehlermeldungen zu beobachten sei. Das harmoniert 
auch gut mit der vielbesungenen Wegwerfgesellschaft.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Mike schrieb:
>>kompilieren ohne jeden Mecker
>
> Wirklich?
Nein, war nur Spass. Eigentlich will ich viel lieber viele LEDs ohne 
Vorwiderstand parallelschalten und damit einen Lauflichtblinker an 
meinen frisierten Plastikroller tackern....
:-)

SCNR,
WK

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.