2015-01-23 7 views
14

Ich weiß es durchaus möglich ist, eine char Array mit einem String-Literal zu initialisieren:Kann ein Zeichen-Array mit einem bedingt ausgewählten String-Literal initialisiert werden?

char arr[] = "foo"; 

C++ 11 8.5.2/1 sagt so:

A char Array (ob schlicht char, signed char oder unsigned char), char16_t array, char32_t Array oder wchar_t Array kann char16_t Stringliteral, 0.123.053 durch einen schmalen Zeichenliteral, initialisiert werden,Zeichenfolge Literal bzw. Wide-String-Literal oder durch ein entsprechend typisiertes String-Literal in geschweiften Klammern. Aufeinander folgende Zeichen des Wertes des Zeichenfolgenliterals initialisieren die Elemente des Arrays. ...

Sie können jedoch das gleiche mit zwei Stringliterale in einem bedingten Ausdruck? Zum Beispiel wie folgt aus:

char arr[] = MY_BOOLEAN_MACRO() ? "foo" : "bar"; 

(Wo MY_BOOLEAN_MACRO() expandiert nach einem 1 oder 0).

Die relevanten Teile ++ 11 5,16 (Conditional-Operator) C sind wie folgt:

1 ... Der erste Ausdruck auf kontextuell bool (Abschnitt 4) umgewandelt wird. Es wird ausgewertet, und wenn es true ist, ist das Ergebnis des bedingten Ausdrucks der Wert des zweiten Ausdrucks andernfalls des dritten Ausdrucks. ...

4 Wenn der zweite und dritte Operand glvalues ​​der gleichen Wertkategorie sind und denselben Typ haben, ist das Ergebnis von diesem Typ und Werttyp und es ist ein Bitfeld wenn der zweite oder der dritte Operand ist ein Bit-Feld, oder wenn beide Bit-Felder sind.

Beachten Sie, dass die Literale die gleiche Länge haben und somit beide Werte vom Typ const char[4] sind.

GCC one ideone akzeptiert das Konstrukt. Aber vom Lesen des Standards bin ich einfach nicht sicher, ob es legal ist oder nicht. Hat jemand einen besseren Einblick?

Antwort

10

Auf der anderen Seite clang akzeptiert keine solchen Code (see it live) und ich glaube, clang auf dieser (MSVC also rejects this code) korrekt ist.

Ein Stringliteral wird durch die Grammatik in Abschnitt 2.14.5:

string-literal: 
    encoding-prefixopt" s-char-sequenceopt" 
    encoding-prefixoptR raw-string 

und der erste Absatz von diesem Abschnitt sagt (Hervorhebung von mir):

Ein Zeichenfolgenliteral ist eine Folge von Zeichen (wie in 2.14.3 definiert) umgeben von Doppelquo tes, optional mit vorangestelltem R, u8, u8R, u, uR, U, UR, L oder LR, wie in "...", R "(...)", u8 "...", u8R "(...)", u "...", uR "~ (...) ~", U "...", UR "zzz (...) zzz", L "... "oder LR"(...)", jeweils

und es sagt ferner, daß der Typ einer schmalen Stringliteral ist:

„Array von n const char ",

sowie:

hat statische Speicherdauer

sondern ein „Array von n const char“ mit statischer Lagerdauer keine Stringliteral ist, da es nicht der Fall ist Passen Sie die Grammatik noch passt Absatz 1.

Wir können dies auf gcc machen scheitern, wenn wir einen nicht konstanten Ausdruck (see it live) verwenden:

bool x = true ; 
char arr[] = x ? "foo" : "bar"; 

was bedeutet es wahrscheinlich eine Erweiterung ist, aber es ist nicht konforme, da es nicht der Fall ist eine Warnung in strict conformance mode dh unter Verwendung -std=c++11 -pedantic erzeugen. Aus dem Bereich 1.4[intro.compliance]:

[...] Implementationen sind erforderlich, Programme zu diagnostizieren, die solche Erweiterungen verwenden, die schlecht ausgebildet sind, nach dieser Internationalen Norm . Nachdem sie dies getan haben, können sie jedoch solche Programme kompilieren und ausführen.

+3

Zustimmen, 8.5.2/1 scheint ziemlich klar, dass es * string literal * und nicht * ein Ausdruck ist, der zu einem String-Literal * auswertet. (auch wenn Sie den ternären Operator in diesem Fall als ein String-Literal bewerten). –

3

Diese in GCC in C++ funktioniert 11 oder neuer weil die Literale Sie bieten während der Kompilierung deterministisch sind (zB sind sie constexpr). Da der Compiler herausfinden kann, welcher wahr ist, darf er herausfinden, welcher zu verwenden ist.

die constexpr Fähigkeit zu entfernen, versuchen, etwas wie folgt aus:

#include <iostream> 
#include <cstdlib> 

int main() { 
    bool _bool = rand(); 
    char arr[] = (_bool) ? "asdf" : "ffff"; 

    std::cout << arr << std::endl; 
} 

GCC dann Fehler aus mit:

g++ test.cpp -std=c++11 
test.cpp: In function ‘int main()’: 
test.cpp:6:34: error: initializer fails to determine size of ‘arr’ 
    char arr[] = (_bool) ? "asdf" : "ffff"; 
           ^
test.cpp:6:34: error: array must be initialized with a brace-enclosed initializer 

Ich weiß nicht, die Textdefinition Standard gut genug, um zu wissen, wo oder Warum das ist gültig, aber ich fühlen, dass es ist gültig.

Weitere Informationen zu constexpr und zur Auswirkung auf die Kompilierbarkeit finden Sie unter the answer by @ShafikYaghmour in another question.

+1

Beachten Sie, dass * constant expression * und * constexpr * verwandt sind, aber nicht das gleiche, ich beziehe das zu einem gewissen Grad [hier] (http://stackoverflow.com/a/26025026/1708801), also behandelt 'gcc' es als ein konstanter Ausdruck. –

+0

Stimmt, ich kann sehen, dass es einen Unterschied gibt. Aber es ist ein guter Punkt, und ich denke nicht, dass der Unterschied in C++ 11 und darüber hinaus gilt ... es sei denn, Sie können zeigen, dass es tut? – inetknght

+1

Es ist rein informativ, hoffentlich finden Sie es hilfreich. Ich würde nur bemerken, dass, da die Frage markiert ist, Sprache-Anwalt Leute neigen, wählerischer über Details zu sein. –