Wie genau funktioniert der Operator ?: In C?

10

Ich habe eine Frage, wie der Compiler mit folgendem Code arbeitet:

#include<stdio.h>

int main(void)
{
  int b=12, c=11;
  int d = (b == c++) ? (c+1) : (c-1);
  printf("d = %i\n", d);
}

Ich bin nicht sicher , warum das Ergebnis ist d = 11.

J0S
quelle
1
Warum bist du dir nicht sicher? Was würden Sie sonst noch erwarten und warum?
Gerhardh
2
Ich erinnere mich nicht an die genaue Semantik, aber Sie beobachten möglicherweise undefiniertes Verhalten.
Chepper
3
Nein, @chepner, es gibt einen Sequenzpunkt nach der Bewertung des Zustands eines Ternärs, bevor die ausgewählte Alternative bewertet wird. Das vermeidet den UB-Vektor, an den Sie vermutlich denken.
John Bollinger
Ja, ich bin mir nicht sicher, wo ich dachte, dass der Compiler eine Wahl haben würde.
Chepper

Antworten:

6

In int d = (b == c++) ? (c+1) : (c-1);:

  • Der Wert von c++ist der aktuelle Wert von c11. Separat cwird auf 12 erhöht.
  • b == 11ist falsch, da bist 12.
  • Da (b == c++)ist falsch, (c-1)wird verwendet. Außerdem muss das Inkrement von cbis zu diesem Punkt abgeschlossen sein.
  • Da cist 12, c-1ist 11.
  • d wird auf diesen Wert initialisiert, 11.
Eric Postpischil
quelle
5

Gemäß dem C-Standard (6.5.15 Bedingter Operator)

4 Der erste Operand wird ausgewertet; Es gibt einen Sequenzpunkt zwischen seiner Auswertung und der Auswertung des zweiten oder dritten Operanden (je nachdem, welcher ausgewertet wird). Der zweite Operand wird nur ausgewertet, wenn der erste ungleich 0 ist; der dritte Operand wird nur ausgewertet, wenn der erste gleich 0 ist; Das Ergebnis ist der Wert des zweiten oder dritten Operanden (je nachdem, welcher Wert ausgewertet wird), konvertiert in den unten beschriebenen Typ.110)

Also im initialisierenden Ausdruck dieser Deklaration

int d = (b == c++) ? (c+1) : (c-1);

Die Variable bwird mit dem Wert der Variablen verglichen, cda der Operator nach dem Inkrementieren den Wert seines Operanden vor dem Inkrementieren zurückgibt.

Da die Werte nicht gleich sind ( bwird auf 12 gesetzt, während cauf 11 gesetzt wird), wird der Unterausdruck (c-1)ausgewertet.

Nach dem Zitat gibt es einen Sequenzpunkt nach Bewertung des Zustands des Bedieners. Dies bedeutet, dass nach Auswertung der Bedingung cder Wert 12nach Anwenden des Post-Inkrement-Operators auf die Variable vorliegt c. Infolgedessen wird die Variable d durch den Wert 1( 12 - 1) initialisiert .

Vlad aus Moskau
quelle
2
Die einzig richtige Antwort - dieser spezielle Fall muss durch Erwähnung des Sequenzpunkts in beantwortet werden ?:. Da normalerweise in C das Kombinieren ++mit anderen Operationen mit demselben Operanden ein undefiniertes Verhalten ist. Und dieser Code funktioniert nur vorhersehbar, da er ?:verschiedene spezielle Schneeflockenregeln hat.
Lundin
4

Weil die Bedingung falsch ist, wird der falseFall eintreten :, c-1aber da Sie cdie Bedingung um erhöht haben c++, cist dies jetzt der Fall 12. Das Ergebnis ist also 12 - 1, was 11 ist.

EDIT: Was OP missverstanden hat, war das Post-Inkrement.

Was also tatsächlich passiert, ist folgender:

#include<stdio.h>
int main(void)
{
  int b=12, c=11;
  int d;

  if (b == c) { // 12 == 11 ? -> false
    c = c + 1;
    d = c + 1;
  } else { // this executes since condition is false
    c = c + 1; // post increment -> c++ -> c = 12 now
    d = c - 1; // 12 - 1 = 11 -> d = 11
  }
  printf("d = %i\n", d);
}
Eraklon
quelle
1
Ich denke, das OP bezieht sich auf die Reihenfolge der Operationen, wenn c++die Bedingung erfüllt ist. Die Bedingung ist falsch, aber dann wird der ursprüngliche Wert von czur Berechnung verwendet c - 1, nicht die inkrementierte Version.
Chepper
1
Ich dachte, dass aufrichtig 12 == 11 + 1 es wahr ist ...
J0S
Aber das stimmt nicht, da der neue c-Wert verwendet wird, oder fehlt mir der Punkt von Ihnen?
Eraklon
Ich denke, es könnte ein Missverständnis zwischen c++und++c
ChatterOne
@ N00b c++ist der Operator nach dem Inkrementieren. Der Wert von c++ist 11, mit dem Nebeneffekt der Herstellung c == 12. ++chätte den Wert 12.
chepner
4

Übersetzt in eine reguläre if-Anweisung würde Ihr Code folgendermaßen aussehen:

int b=12, c=11;
int d;

if (b == c++)
   d = c+1;
else
   d = c-1;

Der Hinweis hier ist, dass c erhöht wird, nachdem die Bedingung überprüft wurde. Sie geben also den elseStatus ein, aber c hat dort bereits den Wert 12.

Odysseus
quelle
1

Siehe Ternary Operator.

Syntax

Bedingung ? value_if_true: value_if_false

Also hast du geschrieben

int d = (b == c++) ? (c+1) : (c-1);

In dieser Situation ist das Ergebnis 11, da nach Überprüfungen der 'c'-Wert erhöht wird (c + 1 = 12) und erst danach der' d'-Wert als c (12) -1 festgelegt wird, was 11 ist.

Wenn Sie zum Beispiel verwendet haben:

int d = (b == ++c) ? (c+1) : (c-1);

Der "c" -Wert würde vor dem Überprüfen der Anweisung erhöht, so dass er wahr wäre und der "d" -Wert c (12) +1 wäre, was 13 ist.

Neto Costa
quelle