Was ist ein konstanter Ausdruck in C?

8

C definiert mindestens 3 Ebenen des "konstanten Ausdrucks":

  • konstanter Ausdruck (unqualifiziert)
  • arithmetischer Konstantenausdruck
  • Integer-Konstantenausdruck

6.6 Absatz 3 lautet:

  

Konstante Ausdrücke dürfen keine Zuweisung, Inkrementierung, Dekrementierung, Funktionsaufruf,   oder Kommaoperatoren, außer wenn sie in einem Teilausdruck enthalten sind, der nicht enthalten ist   ausgewertet.

Also bedeutet das 1,2 ist kein konstanter Ausdruck?

In Absatz 8 heißt es:

  

Ein arithmetischer Konstantenausdruck soll einen arithmetischen Typ haben und nur haben   Operanden, die Integer-Konstanten, Floating-Konstanten, Enumerationskonstanten, Zeichen sind   Konstanten und Größe von Ausdrücken. Übergibt Operatoren in einem arithmetischen Konstantenausdruck   darf nur arithmetische Typen in arithmetische Typen umwandeln, außer als Teil eines Operanden in a   sizeof-Operator, dessen Ergebnis eine Ganzzahlkonstante ist.

Was sind die Operanden in (union { uint32_t i; float f; }){ 1 }.f ? Wenn 1 der Operand ist, dann ist dies vermutlich ein arithmetischer Konstantenausdruck, aber wenn { 1 } der Operand ist, dann ist es eindeutig nicht.

Bearbeiten: Eine weitere interessante Beobachtung: 7.17 Absatz 3 erfordert, dass das Ergebnis von offsetof ein ganzzahliger konstanter Ausdruck vom Typ size_t ist, aber die Standardimplementierungen von offsetof , soweit Ich kann sagen, dass keine konstanten Integer-Ausdrücke nach dem Standard sein müssen. Dies ist natürlich in Ordnung, da eine Implementierung (unter 6.6 Absatz 10) erlaubt ist, andere Formen von konstanten Ausdrücken zu akzeptieren, oder das offsetof -Makro als __builtin_offsetof anstatt über die Zeiger-Subtraktion implementiert. Der Kern dieser Beobachtung ist jedoch, dass Sie, wenn Sie offsetof in einem Kontext verwenden möchten, in dem ein ganzzahliger konstanter Ausdruck benötigt wird, wirklich das von der Implementierung bereitgestellte Makro verwenden und nicht Ihr eigenes rollen müssen.

    
R.. 04.02.2011, 00:11
quelle

2 Antworten

1

Basierend auf Ihrer Lektüre ist 1,2 kein konstanter Ausdruck. Ich weiß nicht, warum es nicht ist, nur dass ich mit dir übereinstimme, dass es nicht ist (trotz der Tatsache, dass es wahrscheinlich sein sollte).

6.5.2 spezifiziert zusammengesetzte Literale als Postfixoperator. Also in

%Vor%

Die Operanden sind (union { uint32_t i; float f; }){ 1 } und f für den Operator . . Es ist kein arithmetischer Konstantenausdruck, da das erste Argument ein union -Typ ist, aber ein konstanter Ausdruck.

UPDATE: Ich habe dies auf eine andere Interpretation des Standards gestützt.

Meine vorherige Argumentation war, dass (union { uint32_t i; float f; }){ 1 }.f die Kriterien für einen konstanten Ausdruck erfüllte und daher ein konstanter Ausdruck war. Ich denke immer noch, dass es die Kriterien für einen konstanten Ausdruck (6.6 Absatz 3) erfüllt, aber dass es keine der Standardtypen von konstanten Ausdrücken (Ganzzahl, Arithmetik oder Adresse) ist und daher nur von 6.6 Absatz als konstanter Ausdruck abhängig ist 10, die implementierungsdefinierte konstante Ausdrücke erlaubt.

Ich wollte auch zu deinem Schnitt kommen. Ich wollte argumentieren, dass die "Hack" -Implementierung von offsetof ein konstanter Ausdruck war, aber ich denke, es ist das gleiche wie oben: Es erfüllt die Kriterien für einen konstanten Ausdruck (und möglicherweise eine Adresskonstante), ist aber keine Ganzzahlkonstante Ausdruck und ist daher außerhalb von Absatz 6.6 ungültig.

    
Chris Lutz 04.02.2011, 00:48
quelle
0

Wenn 1,2 ein konstanter Ausdruck wäre, würde dies Code wie diesen kompilieren:

%Vor%

Ich weiß nicht, ob das der wahre Grund ist, aber ich kann mir vorstellen, dass das Ausgeben eines Fehlers für diesen (häufigen?) Fehler als wichtiger angesehen wurde als das Umwandeln von 1,2 in einen konstanten Ausdruck.

UPDATE : Wie R. in einem Kommentar sagt, ist der Code ab der Einführung von VLAs kein Compilerfehler mehr.

    
Sjoerd 04.02.2011 05:58
quelle