2010-10-02 9 views
7

Hier ist meine Funktion:Funktion übergeben Argumente in umgekehrter

void abc(char *def, unsigned int w, unsigned int x, unsigned int y, unsigned int z) 
{ 
    printf("val 1 : %d\n", w); 
    printf("val 2 : %d\n", x); 
    printf("val 3 : %d\n", y); 
    printf("val 4 : %d\n", z); 
} 

und hier ist, wo ich diese Funktion aufrufen:

unsigned int exp[4] = { 1, 2, 3, 4 }; 
unsigned short count = 0; 
abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]); 

und hier ist die Ausgabe, die ich erwarten:

val1 : 1 
val2 : 2 
val3 : 3 
val4 : 4 

aber was ich bekomme ist völlig umgekehrt:

val1 : 4 
val2 : 3 
val3 : 2 
val4 : 1 

Ich weiß nicht warum? Jede Hilfe wäre willkommen.

+0

Ihr printf ist auch kaputt, es frisst das erste Leerzeichen in der Formatzeichenkette! :) –

Antwort

8

Von Standard docs, 5,4

Soweit nicht anders angegeben, ist die Reihenfolge der Auswertung von Operanden von einzelnen Betreibern und Unterausdrücken einzelner Ausdrücke, und der Reihenfolge, in den Nebenwirkungen stattfinden, unspecified58) Zwischen dem vorherigen und dem nächsten Sequenzpunkt muss der gespeicherte Wert eines skalaren Objekts höchstens einmal durch die Auswertung eines Ausdrucks geändert werden. Darüber hinaus soll auf den vorherigen Wert nur zugegriffen werden, um den Wert zu bestimmen, der gespeichert werden soll.Die Anforderungen dieses Absatzes müssen erfüllt sein für jede zulässige Reihenfolge der Teilausdrücke eines vollständigen Ausdrucks; Andernfalls ist das Verhalten nicht definiert.

Ein Beispiel aus der Standard-Dokumente selbst,

i = v[i ++];// the behavior is undefined

Und es ist aus dem gleichen Grund, dass

abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]); nicht definiert ist ..

-4

Dies ist wegen der Aufrufkonvention. In _cdecl, der Standard-Aufrufkonvention für c/C++ - Programme (nach Microsoft), werden die Parameter auf dem Stack in umgekehrter Reihenfolge an die Funktion übergeben. Aus diesem Grund werden die Parameter auch in umgekehrter Reihenfolge ausgewertet.

+4

Das ist nicht ganz richtig. Im Standard gibt es nichts, was besagt, dass Argumente von rechts nach links an den Stack übergeben werden (zB: wie gcc das tut). Tatsächlich sagt nichts, dass es überhaupt einen Stapel geben muss. – NullUserException

+0

Ich schreibe mein Programm auf 64-Bit-Arch. Also nehme ich hier an, dass Funktionsparameter in Registern gespeichert werden. –

+0

Ja, aber ich spreche über die Aufrufkonvention, die dieser spezielle Compiler verwendet, die am häufigsten zu sein scheint. –

2

Sie haben ein undefiniertes Verhalten aufgerufen, indem Sie count mehr als einmal ohne eine dazwischen liegende sequence point geändert haben.

4

Sie sollten den Operator ++, der mit derselben Variablen arbeitet, nicht mehrmals in derselben Anweisung verwenden. Die Reihenfolge, in der die Operation ausgeführt wird, ist nicht definiert.

Versuchen:

abc(anyarray, exp[count], exp[count+1], exp[count+2], exp[count+3]); 
count += 4; 
+1

'Sie sollten den Operator ++ nicht mehrmals in derselben Anweisung verwenden. Warum können wir nicht? 'c = a ++ + b ++' ist gut definiert. –

+2

@Prasoon: OK, bearbeitet, um diesen Punkt zu adressieren. Aber schicke Mehrfachverwendungen von Inkrementoperatoren führen zu der Art von Problem in der ursprünglichen Frage. Ich würde schreiben c = a + b; a ++; b ++; ich selbst – Andrew

1

Sie zu den Parametern zählen nach rechts ausgewertet gelassen wird. Sie können keine Annahmen über die Reihenfolge machen, in der sie ausgewertet werden. In diesem Fall sieht es so aus, als ob der Compiler sie von rechts nach links auswertet.

Sie können auch Sequenzpunkte nachschlagen, da Sie den Operator ++ möglicherweise nicht auf diese Weise verwenden sollten.

+0

Es gibt kein "kann" darüber. Der Standard benennt genau dieses Ding als ** undefiniertes Verhalten **, was bedeutet, dass der Compiler frei ist, irgendetwas zu tun - sogar um nasale Dämonen zu verursachen. – greyfade

+0

Ja, aber ironisch bedeutet es auch, dass es völlig so funktioniert, wie Sie es erwarten. Sie haben natürlich Recht - das "kann" ist, dass ich es vermeide, in einer Antwort zu präskriptiv zu sein, obwohl in diesem Fall ein wenig Vorschriftsmäßigkeit wahrscheinlich angemessen ist. – jwismar

1

abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]);

Die Reihenfolge der Auswertung der Argumente von abc ist nicht spezifizieren aber der Ausdruck ruft undefiniertes Verhalten, weil Sie eine Variable count mehr als einmal zwischen zwei Sequenzpunkten zu ändern versuchen.

Darüber hinaus ruft UB auch den falschen Formatbezeichner in printf() auf. Bitte stellen Sie sicher, dass Sie korrekte Formatbezeichner (d. H. %u für unsigned int) in printf() verwendet haben.

+1

Es wäre möglich, alle Werte 1 oder auch alle Werte 4 zu erhalten. –

+0

Ich denke, es ist wichtig zu beachten, dass "zählen" ist eine skalare Variable und daher ist es UB. Dies ist kein Problem, wenn UDT gezählt wird – Chubsdad

0

Du hast dies, weil Sie genannt adb(exp,a,b,c,d) nach Ihrem Problem, aber während des Aufrufs der Funktion d wird zuerst auf Stapel geschoben und dann c ,b relativ. Wie Sie exp[count++] am letzten Argument übergeben, das zuerst verarbeitet, um über Stapel zu schieben, bedeutet, dass zuerst 1 dann dann 2 dann 3 dann 4 gedrückt wird. Und in genannter Funktionspop durchgeführt, so erhalten Sie w=4 x=3 y=2 z=1 das ist es.