2013-02-10 21 views
6

Test (c/CPP)Warum sind mehrere Inkremente/Dekremente in C++, aber nicht in C gültig?

#include <stdio.h> 

int main(int argc, char** argv) 
{ 
    int a = 0, b = 0; 
    printf("a = %d, b = %d\n", a, b); 
    b = (++a)--; 
    printf("a = %d, b = %d\n", a, b); 

    return 0; 
} 

Wenn ich die oben als CPP-Datei zu speichern, kompiliert es und gibt diese bei der Ausführung.

a = 0, b = 0 
a = 0, b = 1 

Allerdings, wenn ich es speichern als C-Datei, bekomme ich folgende Fehlermeldung:

test.c:7:12: error: lvalue required as decrement operator. 

Sollte nicht der (++a) Betrieb vor dengelöst werdenBetrieb? Hat jemand dazu einen Einblick?

+4

'b = (++ a) -;' <- ist das nicht ** undefiniertes Verhalten **? – LihO

+3

@LihO: Warum? Das Inkrement von 'a' wird vor der Auswertung sequenziert. –

+0

Warum nicht einfach 'b = a + 1'? –

Antwort

13

In C ist das Ergebnis der Operatoren increase/decrement für Präfix und Postfix kein lvalue.

In C++ ist das Ergebnis des Postfix-Inkrement/Dekrement-Operators ebenfalls kein Lvalue, aber das Ergebnis des Präfix-Inkrement/Dekrement-Operators ist ein Lvalue.

Jetzt etwas tun wie (++a)-- in C++ ist undefiniertes Verhalten, weil Sie einen Objektwert zweimal zwischen zwei Sequenzpunkten ändern.

EDIT: Follow-up auf @ bames53 Kommentar. Es ist undefiniertes Verhalten in C++ 98/C++ 03, aber die Änderungen in C++ 11 auf der Idee der Sequenzpunkte macht jetzt diesen Ausdruck definiert.

+3

C++ 11 beseitigt Sequenzpunkte und erfordert stattdessen nur, dass die Lese- und Modifikationsfolgen geordnet sind, die sie in '(++ a) -' sind. Siehe [hier] (http://stackoverflow.com/q/10655290/365496) – bames53

+0

Mit der Behauptung, dass "(++ a) -" ist wohldefiniert. Die Seite, auf die bames53 verweist, würde auf '- (++ a)' angewendet, aber post-increment hat nicht dieselbe Sequenz –

+0

@MM Die Nebenwirkungen von '++ a' in' (++ a) - ' sind relativ zum Postfix '--' nach C++ 11, 5.17p1 sequenziert: *" In allen Fällen wird die Zuweisung nach der Wertberechnung der rechten und linken Operanden und vor der Wertberechnung des Zuweisungsausdrucks sequenziert . "* (mit 5.3p2 *" Wenn x nicht vom Typ bool ist, entspricht der Ausdruck ++ x x + = 1 "*). – ouah

3

In C und C++ gibt es lvalue-Ausdrücke, die auf der linken Seite des =-Operators und rvalue-Ausdrücke verwendet werden können, die nicht können. C++ erlaubt mehr Dinge als lvalues, weil es Referenzsemantiken unterstützt.

Die Inkrement- und Dekrementoperatoren ähneln der Zuweisung, da sie ihr Argument ändern.

In C++ 03, (++a)-- würde undefiniertes Verhalten verursachen, weil zwei Operationen, die nicht in Bezug aufeinander sequenziert werden, die gleiche Variable ändern. (Auch wenn ein „pre“ und ist „post“, sie unsequenced sind, weil es keine , ist, &&, ? oder so.)

In C++ 11, hat der Ausdruck jetzt, was man erwarten würde . Aber C11 ändert keine solchen Regeln, es ist ein Syntaxfehler.

+0

"weil es Referenzsemantik unterstützt" Es ist einfach, weil C die Operatoren nicht als lval definiert hat. – bames53

+0

@ bames53 Das ist ein Mittel zum Zweck ... – Potatoswatter

0

§5.2.7 erhöhen bzw. verringern:

The value of a postfix ++ expression is the value of its operand. [ ... ]  The operand shall be a modifiable lvalue.

Der Fehler, den Sie in Ihrem C-Kompilierung erhalten hilft, lassen vermuten, dass dies nur eine Funktion in C++.

2

Für alle, die die genauen Details der Unterschiede wollen könnten, wie sie in den Normen angegeben sind, C99, §6.5.3/2 sagt:

The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation.

dagegen 11 ++ C, § 5.3.2/1 sagt:

The result is the updated operand; it is an lvalue, and it is a bit-field if the operand is a bit-field.

[Hervorhebung hinzugefügt, in beiden Fällen]

Beachten Sie auch, dass, obwohl (++a)-- gibt nicht definiertes Verhalten (zumindest in C++ 03), wenn a ein int ist, wenn a ist einige benutzerdefinierten Typ, so dass Sie Ihre eigenen Überlastungen von ++ und -- verwenden, wird das Verhalten definiert werden - in einem solchen Fall sind Sie das Äquivalent zu bekommen:

a.operator++().operator--(0); 

Da jeder Operator zu einem Funktionsaufruf führt (der sich nicht überschneiden kann), haben Sie do Sequenzpunkte, um definiertes Verhalten zu erzwingen (beachten Sie, dass ich seine Verwendung nicht empfehle, sondern nur, dass das Verhalten in diesem Fall tatsächlich definiert ist)).