Hallo zusammen,
ich bin gerade dabei mich in fremden Code einzuarbeiten und dabei auf
folgendes gestossen:
int func(void)
{
u16 ret;
int status;
status = func2(&ret);
return status ? : ret; // Diese Zeile verstehe ich nicht
}
Prinzipiell kenne ich ka die verkürzte if Schreibweise so:
x ? y : z
FALLS x DANN y SONST z
* Irgendwie fehlt mir hier der DANN Zweig
* Der SONST Zweig würde u16 zurückgeben und kein int
Hat irgendwer einen Rat?
Danke, Michael
Die Zeile ist ausgeschrieben
Wenn status dann <nichts> sonst ret.
Der Returnwert ist also leer oder ret wenn nicht status.
int kann auch ein u16 sein, kommt auf die Plattform an.
Gruß
Fabian
Michael D. schrieb:> return status ? : ret; // Diese Zeile verstehe ich nicht> Prinzipiell kenne ich ka die verkürzte if Schreibweise so:>> x ? y : z> Hat irgendwer einen Rat?
IMHO ist das ein Fehler.
Da wirst du wohl die Funktion analysieren müssen um festzustellen, was
ein sinnvoller Returnwert im Falle von status ist.
Aber eine int Funktion kann nicht einfach <nichts> zurückgeben.
A. K. schrieb:> x ? : y ist eine GCC spezifische Abkürzung für x ? x : y>> http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Conditionals.html#Conditionals
Schrecklich. Warum macht man sowas? Da sind meines Erachtens Fehler
vorprogrammiert, wenn der Compiler etwas akzeptiert, was eigentlich eher
ein Syntax-Error ist.
Jedenfalls sah es Karl Heinz bis eben noch genauso :-)
Okay, die Argumentation, man könne damit einen Side-Effect vermeiden,
nämlich die Wiederholung von Ausdrücken in Makros und damit eine
zweifache Evaluation des Ausdrucks, kann ich ja noch nachvollziehen.
Aber dieses Problem zu erschlagen mit einer "Erweiterung" der Syntax des
?-Operators halte ich für grenzwertig.
Gruß,
Frank
Frank M. schrieb:> Schrecklich. Warum macht man sowas? Da sind meines Erachtens Fehler> vorprogrammiert, wenn der Compiler etwas akzeptiert, was eigentlich eher> ein Syntax-Error ist.
Ich sehe das weit weniger kritisch. "Vorprogrammierte Fehler" weil der
Compiler Dinge akzeptiert, die nicht dem Standard entsprechen, klingt
für mich etwas nach Panik.
Manche GCC Erweiterungen sind/waren Versuchsballons, die teilweise
später in C99 eingeflossen sind.
Aber dann schreib halt -ansi -pedantic-errors rein und du bist es los.
Schon oft habe ich gelesen, dass die ?-Anweisung eine Kurzschreibweise
für if sein soll. Kann ich aber gar nicht bestätigen.
bei if wird eine Bedingung ausgewertet und bei zutreffen der
"then"-Zweig ausgeführt, bei Nicht-Zutreffen - falls vorhanden - der
Else-Zweig.
Im Gegensatz dazu nimmt der ?-Ausdruck einen Wert in Abhängigkeit der
Bedingung an, damit sind Sachen wie
neu=bedingung?17:25
möglich.
Mit if würde das heißen:
if(bedingung)neu=17;else neu=25
Aber ich kann es auch in einen Funktionsaufruf legen:
funktion(kalt?wärmen:kühlen)
In if-Schreibweise
if(kalt)funktion(wärmen);else funktion(kühlen)
So gern ich die ?:-Syntax mag, die Implementierung im Compiler habe ich
oft ineffektiv gesehen.
Karl heinz Buchegger schrieb:> Aber eine int Funktion kann nicht einfach <nichts> zurückgeben.
In PHP geht das sehr wohl. Da kann man auch wild verschiedene Datentüpen
innerhalb der Funktion zurückgeben unter anderem auch "nichts" wobei das
einfach darin resultiert das man null/false/0 bekommt (je nach
Auswertung). Er hat ja nicht geschrieben das es um C und GCC handelt ;P
JS kennt es auch, das funktionen nicht immer einen (expliziten)
Returnwert haben.
eProfi schrieb:> So gern ich die ?:-Syntax mag, die Implementierung im Compiler habe ich> oft ineffektiv gesehen.
Mit hochoptimierten Compilern und Profiling, wo wenig verwendete
Codezweige weggeschoben werden, hat sich das geändert. Ganz besonders
aber bei Architekturen mit bedingter Ausführung von Befehlen (z.B. ARM)
war das von Anfang an recht effizient umsetzbar.
eProfi schrieb:> Aber ich kann es auch in einen Funktionsaufruf legen:> funktion(kalt?wärmen:kühlen)
Abgesehen von den Umlauten natürlich schon. Wenn gern etwas
unkonventioneller sein darf, dann auch so:
(kalt?waermen:kuehlen)(10);
Der historische Hintergrund von ?: ist aber weniger eine
Kurzschreibweise von if/else. Vielmehr liessen sich nur so wichtige
Funktionen wie getc(f) effizient als Makros implementieren - inlining
per Präprozessor. Heute kann man das mit ganz offiziellen
Inline-Funktionen sprachlich eleganter umsetzen.
Frank M. schrieb:> Schrecklich. Warum macht man sowas? Da sind meines Erachtens Fehler> vorprogrammiert
Ich finde es zwar auch schrecklich in diesem Falle :), aber Fehler
sind hier keineswegs programmiert. Die meisten C-Programmierer
meiden den ternären Operator wie der Teufel das Weihwasser, weil sie
ihn nie so gut verstanden haben, dass sie ihn "flüssig lesen" können.
Die paar, die ihn benutzen, sind sich daher in ihrer Sache relativ
sicher, und solange kein anderer Compiler auf die Idee kommt, den
weggelassenen ersten Teil als eine völlig andere Erweiterung zu
definieren, schmeißt er einfach nur einen Syntaxfehler, ist also
auch kein Portabilitätsproblem.
Wenn man die GCC-Erweiterungen nicht haben will, sollte man halt
immer mit »-std=c99 -Wall -Wextra -pedantic« compilieren.
Warum man sowas implementiert, ist auch klar: weil die Situation,
dass man ein fehlendes Ergebnis durch etwas anderes ersetzen will,
im praktischen Leben offenbar häufig man auftritt. (Allerdings kannte
ich diese GCC-Erweiterung bis soeben auch noch nicht.)
Jörg Wunsch schrieb:> im praktischen Leben offenbar häufig man auftritt. (Allerdings kannte> ich diese GCC-Erweiterung bis soeben auch noch nicht.)
Recht verbreitet ist diese Technik als || Operator in Perl, der ja kein
logisches 0/1 erzeugt, sondern die Operanden durchreicht.
Jörg Wunsch schrieb:> Warum man sowas implementiert, ist auch klar: weil die Situation,> dass man ein fehlendes Ergebnis durch etwas anderes ersetzen will,> im praktischen Leben offenbar häufig man auftritt.
Kann ich mir nicht so richtig vorstellen.
Die Bedingung darf dann kein Vergleich sein, sondern muß ein Wert sein.
Und nur der Wert 0 wird dann durch was anderes ersetzt.
Ist die Bedingung ein Vergleich, dann spart man gerade mal das Schreiben
der "1" ein.
Die Rückgabe eines Vergleichs erzeugt oftmals mehr Code als ein Sprung
bei !=0, da dann ja explizit nach 0/1 gewandelt werden muß.
Peter
Jörg Wunsch schrieb:> Warum man sowas implementiert, ist auch klar: weil die Situation,> dass man ein fehlendes Ergebnis durch etwas anderes ersetzen will,> im praktischen Leben offenbar häufig man auftritt. (Allerdings kannte> ich diese GCC-Erweiterung bis soeben auch noch nicht.)
Ditto.
Ich werde das auch in weiterer Folge nicht verwenden. Mir genügt es in
solchen Fällen eine Hilfsvariable zu Hilfe zu nehmen, die mir das
Zwischenergebnis aufnimmt.
Und dort, wo der ternäre Operator tatsächlich unglaublich praktisch ist
(in Argumentlisten von Funktionsaufrufen) hab ich selten komplizierte
Ausdrücke, deren doppelte Evaluierung es zu vermeiden gilt.
Das es derartige Erweiterungen hauptsächlich nur im gcc gibt, hat einen
anderen Grund:
Jemand überlegt sich eine Spracherweiterung, die er vernünftig und gut
findet. Nun kann nicht einfach jeder kommen und die Sprache C erweitern.
Da gibt es Normungsgremien, die solche Dinge beschliessen. Dort wird ein
Antrag auf Änderung eingereicht (samt Begründung, Auswirkungen etc) und
das Gremium beschliesst oder beschliesst nicht, dass diese Änderung in
den offiziellen Sprachstandard eingebracht wird.
Nun ist es aber so, dass die Chancen einen derartigen Antrag
durchzubringen enorm steigen, wenn man einen Compiler vorweisen kann,
der diese Erweiterung bereits enthält. Man dokumentiert damit ,dass die
Spracherweiterung prinzipiell machbar ist, mit den bisherigen C-Regeln
nicht in Konflikt steht und kann anhand von realen Beispielprogrammen
die Erweiterung auch in Aktion zeigen. Kurz und gut: Reicht man den
Antrag ein, ist es extrem hilfreich einen gepatchten Compiler zur
Verfügung zu haben. Und da bietet sich der gcc natürlich an.
Es gibt aber auch durchaus sehr praktische GCC-Erweiterungen, z.B. die
Bereichsangaben bei switch/case.
Ansonsten 65536 Cases hinschreiben zu müssen, macht den Code nicht
gerade lesbarer.
Und diese unsäglichen else/if Monster auch nicht. Sie werden auch lange
nicht so effektiv optimiert, wie switch/case mit Bereichen.
Peter
Peter Dannegger schrieb:> Es gibt aber auch durchaus sehr praktische GCC-Erweiterungen, z.B. die> Bereichsangaben bei switch/case.
Ja, finde ich auch. Wenn muss man denn nerven, damit wir das mal
im C1x wiederfinden werden? ;-)