im Zuge der Arbeit am C-Projekt für die Uni (vorhin abgegeben, jetzt hoffentlich fehlerfrei und funktionstüchtig) ist mir ein Punkt an C bzw. am C-Compiler (ich nutze gcc 4.0.1) aufgefallen, der mir ein wenig seltsam vorkommt.
Es geht um eine Funktion mit definiertem Rückgabetyp, die aber nicht immer auch einen Wert zurück gibt. Bspw. folgendes:
Die Funktion foo liefert in diesem Fall gar nichts zurück und ich hatte zuerst angenommen, daß daher i seinen ursprünglichen Wert beibehält.
In meinem Fall hatte ich danach die Rückgabe daraufhin überprüft ob ein Fehler im Funktionsaufruf auftrat (dann liefert die Funktion 1 zurück), was selbst bei normaler Ausführung (also wenn kein Fehler auftrat) keinerlei Fehlermeldungen oder Programmabstürze verursacht hat.
Dennoch hat eine Analyse des Programms mit valgrind diesen Umstand moniert.
Meine Frage ist jetzt, gibt es eine Konvention oder eine sonstige Regel im C-Standard die besagt, was i hier im Beispiel nach dem Funktionsaufruf für einen Wert haben soll, oder ist das unbestimmt und letztlich dem Zufall überlassen?
Und falls es dafür keinen vorgeschriebenen Weg gibt, wieso moniert der Compiler diesen Umstand nicht und gibt zumindest eine Warnung aus?
Weiß da jemand genaueres?
Ohne das zeigt er doch nur wirkliche Fehler und kritische Warnings an.
Der obige Code ist ja valide, auch wenn du dich darauf verlaesst, dass der Rueckgabewert ggf unspezifiziert ist. (Wahrscheinlich ist das als Implementationsabhaengig markiert)
Koennte ja sein, dass der Programmierer das beruecksichtigt hat (z.B. alle moeglichen Faelle mit if abgefragt hat, bevor das Ende der Funktion erreicht ist).
C geht erstmal davon aus, dass der Programmierer WEISS, was er tut. Daher ist -Wall eine gute Idee.
Mein gcc version 4.2.3 liefert mir mit -Wall jedenfalls folgendes:
Ohne -Wall schweigt es jedoch in Ehrfurcht vor meinen Programmierskillz.
Meine Frage ist jetzt, gibt es eine Konvention oder eine sonstige Regel im C-Standard die besagt, was i hier im Beispiel nach dem Funktionsaufruf für einen Wert haben soll, oder ist das unbestimmt und letztlich dem Zufall überlassen?
Und falls es dafür keinen vorgeschriebenen Weg gibt, wieso moniert der Compiler diesen Umstand nicht und gibt zumindest eine Warnung aus?
Weiß da jemand genaueres?
...
Gleich zu Beginn: Ich bin weder der größte Experte bei noch Fan von C, daher ist meine Antwort mit Vorsicht zu genießen und besser erst aufzunehmen, wenn jemand "Stimmt so" drunter schreibt.
Aber ich denke, das kommt einfach drauf an, welche Compilerflags du verwendest. Mit -ansi -pedantic -Wall sollte er eigentlich schon meckern, bzw. es gar nicht erst kompilieren, wenn eine Funktion entgegen des Headers nichts zurückgibt, daher kann das drüberliegende Problem gar nicht auftreten.
Ohne die Flags ist GCC aber gerade mal ein etwas höherer Assembler, sprich: er setzt die Statements in Maschinencode um, ohne groß was zu prüfen. Daher wird er bei der Funktion, wenn sie nicht mit 1 aufgerufen wird, einfach zurückspringen, ohne was ins Return-Register zu schreiben. Das aufrufende Statement kann das aber natürlich nicht ahnen und weist i daher den Wert des Return-Registers zu, was auch immer der sein mag. Resultat: Chaos. *shrug*
Also, was ich denke: Falls es erfolgreich kompiliert ist das Ergebnis undefiniert, aber mit den richtigen Flags sollte sowas gar nicht erst kompilieren. Und wenn man schon in C programmiert, sollte man die Flags auch tunlichst verwenden, um zumindest einen Teil der Riesenmenge an üblichen Bugs zu vermeiden.
Edit: OK, dann höre einfach auf den, der sich auskennt. XD
--
A human is a system for converting dust billions of years ago into dust billions of years from now via a roundabout process which involves checking email a lot.
Du hast ganz recht und im Grunde haben wir ja vollkommen das selbe gesagt. Nur war ich nen Tick schneller
@ Topic
Da das Thema jetzt ja geklaehrt ist, koennte man diesen Thread ja zu einem Thread ueber Programmierfallstricke umfunktionieren. Ich bin naemlich letztens erst ueber ein Produkt eigener Dummheit gestolpert:
Jeder kennt das: Man hat ein mathematisches Konstrukt ausgearbeitet und uebertraegt das auf C(++). Alles scheint zu funktionieren, doch nach wochen oder Monaten faellt einem was auf, dass der Code nicht so tut, wie er tun sollte, und manchmal seltsamen Mist ausgibt ... Nach aufwaendigem Debuging meines mehere tausend Zeilen langen Codes ueber mehere Dateien bin ich dann auf folgendes gestossen:
Sieht soweit gar nicht verkehrt aus, und -Wall meckert auch nicht rum.
Nur leider gehen hier die Vorstellungen von Naturwissenschaftler und Compiler auseinander:
Der Naturwissenschaftler liest: Der Compiler liest: oder mit anderen Worten: oder fuer Leute ohne C-Syntax: Das das nicht gaaanz das Selbe ist, war mir dann auch klar. MMn waere das auch ein klassischer Kandidat fuer ein -Wall gewesen, denn wann will man schon mal die zweite Interpretation haben ?
Meine Frage ist jetzt, gibt es eine Konvention oder eine sonstige Regel im C-Standard die besagt, was i hier im Beispiel nach dem Funktionsaufruf für einen Wert haben soll, oder ist das unbestimmt und letztlich dem Zufall überlassen?
...
ANSI-C:
Zitat von http://flash-gordon.me.uk/ansi.c.txt
If a return statement without an expression is executed, and the
value of the function call is used by the caller, the behavior is
undefined. Reaching the } that terminates a function is equivalent to
executing a return statement without an expression.
...
Zitat von Ineluki
Das das nicht gaaanz das Selbe ist, war mir dann auch klar. MMn waere das auch ein klassischer Kandidat fuer ein -Wall gewesen, denn wann will man schon mal die zweite Interpretation haben ?
...
Na immer, wenn man sowas schreibt.
Das ist doch eine vollkommen valide Verkettung von Ausdrücken, wobei das Ergebnis des vorhergehenden Ausdrucks ein Operand des folgenden Ausdrucks ist. Vergleichsoperatoren liefern als Ergebnis immer einen Booleschen Wert, da bei dir die Variablen aber vom Typ double sind, muss der Boolesche Wert natürlich erst implizit in einen double-Wert konvertiert werden. Solange der ursprüngliche Wert nicht verändert und der Wertebereich nicht abgeschnitten wird, sind implizite Konvertierungen auch absolut in Ordnung und kein Compiler wird da eine Warnung generieren.
Meiner Meinung nach keine Warnung wert, da nur ein Verständnisproblem deinerseits.
Zitat von drunken monkey
Stimmt, da wäre es sinnvoll, zu meckern, genau wie bei:
(Dort meckern ja afaik auch die meisten Compiler in den meisten Sprachen.)
...
Auch so eine Sache. Das ist vollkommen valides C/C++ und kein Compiler wird da eine Warnung ausgeben. Sogar das strikte Java erlaubt Zuweisungen innerhalb des Bedingungsblocks, wenn die Operanden vom Typ boolean sind.
Meiner Meinung nach ein typischer Anfängerfehler, falls "==" statt "=" gemeint war, manchmal zwar auch ein Tippfehler, bei erfahrenen Programmierern sollte so ein Fehler aber sofort ins Auge stechen, also auch keine Warnung wert, vor allem da valide und oft nützlich.