Ich muss so etwas in C machen. Es funktioniert nur, wenn ich ein Zeichen verwende, aber ich brauche einen String. Wie kann ich das machen?
#define USER "jack" // jack or queen
#if USER == "jack"
#define USER_VS "queen"
#elif USER == "queen"
#define USER_VS "jack"
#endif
c
conditional
c-preprocessor
frx08
quelle
quelle
Antworten:
Ich glaube nicht, dass es eine Möglichkeit gibt, String-Vergleiche mit variabler Länge vollständig in Präprozessor-Direktiven durchzuführen. Sie könnten vielleicht Folgendes tun:
Oder Sie können den Code ein wenig umgestalten und stattdessen C-Code verwenden.
quelle
#define USER_VS (3 - USER)
in diesem speziellen Fall. :)[UPDATE: 2018.05.03]
CAVEAT : Nicht alle Compiler implementieren die C ++ 11-Spezifikation auf dieselbe Weise. Der folgende Code funktioniert in dem Compiler, auf dem ich getestet habe, während viele Kommentatoren einen anderen Compiler verwendeten.
Zitat aus Shafik Yaghmours Antwort unter: Berechnung der Länge eines C-Strings zur Kompilierungszeit. Ist das wirklich ein constexpr?
Dieses Wort
can
macht den Unterschied in der Welt.Also, YMMV zu dieser (oder einer beliebigen) Antwort
constexpr
, die abhängig von der Interpretation der Spezifikation durch den Compiler-Autor beinhaltet.[AKTUALISIERT am 31.01.2016]
Da einige meine frühere Antwort nicht mochten, weil sie den gesamten Aspekt des OP vermieden hat,
compile time string compare
indem das Ziel erreicht wurde, ohne dass Zeichenfolgenvergleiche erforderlich waren, finden Sie hier eine detailliertere Antwort.Das kannst du nicht! Nicht in C98 oder C99. Nicht einmal in C11. Keine MACRO-Manipulation wird dies ändern.
Die Definition von
const-expression
verwendet in#if
erlaubt keine Zeichenfolgen.Es erlaubt Zeichen. Wenn Sie sich also auf Zeichen beschränken, können Sie Folgendes verwenden:
Sie können! In C ++ 11. Wenn Sie eine Kompilierungszeit-Hilfsfunktion für den Vergleich definieren.
Letztendlich müssen Sie also die Art und Weise ändern, in der Sie Ihr Ziel erreichen, die endgültigen Zeichenfolgenwerte für
USER
und auszuwählenUSER_VS
.In C99 können Sie keine Vergleiche zur Kompilierungszeit von Zeichenfolgen durchführen, aber Sie können die Auswahl der Zeichenfolgen zur Kompilierungszeit durchführen.
Wenn Sie wirklich Vergleiche zum Kompilieren von Zeitstichen durchführen müssen, müssen Sie zu C ++ 11 oder neueren Varianten wechseln, die diese Funktion zulassen.
[ORIGINAL ANTWORT FOLGT]
Versuchen:
UPDATE: Das Einfügen von ANSI-Token ist manchmal weniger als offensichtlich. ;-D
Wenn Sie ein einzelnes
#
vor ein Makro stellen, wird es in eine Zeichenfolge mit seinem Wert anstelle seines bloßen Werts geändert.Wenn Sie
##
zwischen zwei Token ein Double setzen , werden diese zu einem einzigen Token verkettet.Das Makro
USER_VS
hat also die Erweiterungjack_VS
oderqueen_VS
, je nachdem, wie Sie es einstellenUSER
.Das Stringify- Makro
S(...)
verwendet die Makro-Indirektion, sodass der Wert des benannten Makros in eine Zeichenfolge konvertiert wird. anstelle des Namens des Makros.So
USER##_VS
wirdjack_VS
(oderqueen_VS
), je nachdem wie Sie einstellenUSER
.Wenn später das Stringify- Makro als
S(USER_VS)
Wert vonUSER_VS
(jack_VS
in diesem Beispiel) verwendet wird, wird es an den Indirektionsschritt übergebenS_(jack_VS)
, der seinen Wert (queen
) in einen String konvertiert"queen"
.Wenn Sie festlegen
USER
,queen
ist das Endergebnis die Zeichenfolge"jack"
.Informationen zur Token-Verkettung finden Sie unter: https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html
Informationen zur Konvertierung von Token-Zeichenfolgen finden Sie unter: https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
[AKTUALISIERT am 15.02.2015, um einen Tippfehler zu korrigieren.]
quelle
#if 0 == c_strcmp( USER, JACK )
zuconstexpr int comp1 = c_strcmp( USER, JACK );
#if 0 == comp1
#if
Ihr Beispiel funktioniert nur, weil USER JACK ist. Wenn USER QUEEN wäre, würde es sagenUSER IS QUEEN
undUSER_VS IS QUEEN
constexpr
) aus Präprozessoranweisungen aufrufen .Das Folgende hat bei mir mit Klirren funktioniert. Ermöglicht den symbolischen Makrowertvergleich. #error xxx ist nur um zu sehen, was der Compiler wirklich macht. Das Ersetzen der Katzendefinition durch #define cat (a, b) a ## b bricht die Dinge.
quelle
Verwenden Sie numerische Werte anstelle von Zeichenfolgen.
Verwenden Sie zum Konvertieren der Konstanten JACK oder QUEEN in eine Zeichenfolge die Operatoren stringize (und / oder tokenize).
quelle
Wie bereits oben erwähnt, wird die ISO-C11 - Präprozessor nicht String - Vergleich unterstützen. Das Problem der Zuweisung eines Makros mit dem "entgegengesetzten Wert" kann jedoch mit "Token-Einfügen" und "Tabellenzugriff" gelöst werden. Jesses einfache Makro-Lösung zum Verketten / Stringifizieren schlägt mit gcc 5.4.0 fehl, da die Stringisierung vor der Auswertung der Verkettung erfolgt ( gemäß ISO C11). Es kann jedoch behoben werden:
In der ersten Zeile (Makro
P_()
) wird eine Indirektion hinzugefügt , damit die nächste Zeile (MakroVS()
) die Verkettung vor der Stringisierung beendet (siehe Warum benötige ich für Makros eine doppelte Indirektionsebene? ). Die Stringisierungsmakros (S()
undS_()
) stammen von Jesse.Die Tabelle (Makros
jack_VS
undqueen_VS
), die viel einfacher zu pflegen ist als die Wenn-Dann-Sonst-Konstruktion des OP, stammt von Jesse.Schließlich ruft der nächste vierzeilige Block die Makros im Funktionsstil auf. Der letzte vierzeilige Block stammt aus Jesses Antwort.
Das Speichern des Codes in
foo.c
und das Aufrufen des Präprozessorsgcc -nostdinc -E foo.c
ergeben:Die Ausgabe ist wie erwartet. Die letzte Zeile zeigt, dass das
USER_VS
Makro vor der Stringisierung nicht erweitert wird.quelle
#if (S(USER)=="jack")
- Ich erhalte einen Präprozessorfehler, wenn ich"
- verwendeerror: invalid token at start of a preprocessor expression
.Wenn Ihre Zeichenfolgen (wie in Ihrem Fall) Kompilierungszeitkonstanten sind, können Sie den folgenden Trick verwenden:
Der Compiler kann das Ergebnis des strcmp im Voraus mitteilen und ersetzt das strcmp durch das Ergebnis, sodass Sie eine #define erhalten, die mit Präprozessor-Direktiven verglichen werden kann. Ich weiß nicht, ob es Unterschiede zwischen Compilern / Abhängigkeit von Compileroptionen gibt, aber es hat bei GCC 4.7.2 für mich funktioniert.
BEARBEITEN: Nach weiteren Untersuchungen sieht es so aus, als wäre dies eine Toolchain-Erweiterung, keine GCC-Erweiterung. Berücksichtigen Sie dies also ...
quelle
$
eine Art Pre-Prozessor-Erweiterung?Die Antwort von Patrick und Jesse Chisholm brachte mich dazu, Folgendes zu tun:
Anstatt
#define USER 'Q'
#define USER QUEEN
sollte auch funktionieren, wurde aber nicht getestetfunktioniert auch und ist möglicherweise einfacher zu handhaben.EDIT: Nach dem Kommentar von @ Jean-François Fabre habe ich meine Antwort angepasst.
quelle
(s==QUEEN?1:0)
durch(s==QUEEN)
Sie brauchen nicht das ternäre, Ergebnis ist bereits ein Boolescher WertEs handelt sich im Grunde genommen um ein statisches Zeichenarray mit fester Länge, das manuell initialisiert wird, anstelle eines statischen Zeichenarrays mit variabler Länge, das automatisch initialisiert wird und immer mit einem abschließenden Nullzeichen endet
quelle
Es ist einfach, denke ich, kann man einfach sagen
quelle