Wie definiere ich ein String-Literal in der gcc-Kommandozeile?

79

In der gcc-Befehlszeile möchte ich eine Zeichenfolge definieren, z. B. -Dname=Maryim Quellcode, den ich printf("%s", name);drucken möchte Mary.
Wie könnte ich das machen?

Richard
quelle
7
Ich empfehle dringend, all-caps ( -DNAME=\"Mary\") für Token zu verwenden, die Sie auf diese Weise definieren, damit sie wie andere Makros aussehen.
JSB 9
Das Makro in der String-Frage: stackoverflow.com/questions/240353/…
Ciro Santilli 6 冠状 病 六四 事件 6

Antworten:

97

Zwei Optionen. Entferne zuerst die Anführungszeichen, damit die Shell sie nicht frisst:

gcc -Dname=\"Mary\"

Oder wenn Sie wirklich -Dname = Mary wollen, können Sie es stringisieren, obwohl es ein bisschen hacky ist.

#include <stdio.h>

#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)


int main(int argc, char *argv[])
{
    printf("%s", STRINGIZE_VALUE_OF(name));
}

Beachten Sie, dass STRINGIZE_VALUE_OF bis zur endgültigen Definition eines Makros problemlos ausgewertet wird.

Arthur Shipkowski
quelle
Vielen Dank Arthur. Sie müssen ein Experte in C. weitere Frage sein: Ich bevorzuge die zweite Option. Wenn ich STRINGIZE_VALUE_OF (Name) verwende, wird es in "1" übersetzt, falls ich gcc -Dname = Mary -DMary habe. gibt es sowieso, um gcc aufhören zu lassen, Mary zu
interpretieren
Richard, nach langem Hin und Her glaube ich nicht, dass ich einen Weg finden kann, der im obigen Beispiel funktioniert. Leider haben Sie keine Auswahl (z. B. "Name") und keine vollständige Erweiterung (z. B. Name-> Mary-> 1, wenn Mary als 1 definiert ist). Abhängig von Ihrem genauen Anwendungsfall kann es Möglichkeiten geben, dies zu umgehen - wenn Mary beispielsweise eher eine Konstante als eine Definition werden kann.
Arthur Shipkowski
Kann jemand eine Begründung dafür geben, warum Sie solche verschachtelten Stringifizierungsmakros verwenden müssen? Es scheint, dass das Ergebnis dasselbe sein sollte, aber das Aufrufen von STRINGIZE_VALUE_OF () scheint die Makroerweiterung des Arguments zu erzwingen, während STRINGIZE () dies nicht tut.
Ionoclast Brigham
1
@IonoclastBrigham, habe das bis heute nicht gesehen. Ein Teil davon ist, dass Sie manchmal Barewords stringisieren möchten - in vielen Fällen wird stringize beispielsweise verwendet, um assert () so zu implementieren, dass der genaue Ausdruck, den Sie haben, ausgedruckt werden kann. In diesem Fall möchten Sie, dass Makros nicht erweitert werden. Sobald Sie feststellen, dass eine Basis-Stringisierung auf diese Weise funktioniert, erzwingt die Verschachtelung eine zweite Runde der Makroerweiterung.
Arthur Shipkowski
29

Um zu vermeiden, dass die Shell die Anführungszeichen und andere Zeichen "frisst", können Sie einzelne Anführungszeichen wie folgt versuchen:

gcc -o test test.cpp -DNAME='"Mary"'

Auf diese Weise haben Sie die volle Kontrolle darüber, was definiert ist (Anführungszeichen, Leerzeichen, Sonderzeichen und alles).

Johann
quelle
8

Die tragbarste Methode, die ich bisher gefunden habe, ist die Verwendung \"Mary\"- sie funktioniert nicht nur mit gcc, sondern mit jedem anderen C-Compiler. Wenn Sie beispielsweise versuchen, /Dname='"Mary"'mit dem Microsoft-Compiler zu arbeiten, wird dieser mit einem Fehler beendet, /Dname=\"Mary\"funktioniert jedoch.

Psihodelia
quelle
6

In Ubuntu habe ich einen Alias ​​verwendet, der CFLAGS definiert, und CFLAGS hat ein Makro enthalten, das eine Zeichenfolge definiert, und dann habe ich CFLAGS in einem Makefile verwendet. Ich musste den doppelten Anführungszeichen und den \ Zeichen entkommen. Es sah ungefähr so ​​aus:

CFLAGS='" -DMYPATH=\\\"/home/root\\\" "'
Samuel
quelle
2
Manchmal funktionierte sowohl das einfache Entkommen als auch das Umschließen in einfache Anführungszeichen nicht, aber das tat es. Andere Male tat es nicht. Ich denke, der Unterschied besteht darin, ob die Flags insgesamt in Anführungszeichen gesetzt werden: Die 1) DEFINES=-DLOGPATH=\"./logfile\" CFLAGS = -v $(DEFINES).... 2) DEFINES=-DLOGPATH=\\\"./logfile\\\" CFLAGS = "-v $(DEFINES)...." Verwendung der Compileroption -v ist nützlich, um zu sehen, was der Präprozessor tut.
Den-Jason
3

Hier ist ein einfaches Beispiel:

#include <stdio.h>
#define A B+20 
#define B 10
int main()
{
    #ifdef __DEBUG__
        printf("__DEBUG__ DEFINED\n");
        printf("%d\n",A);
    #else
        printf("__DEBUG__ not defined\n");
        printf("%d\n",B);
    #endif
    return 0;
}

Wenn ich kompiliere:

$gcc test.c

Ausgabe:

__DEBUG__ not defined
10

Wenn ich kompiliere:

$gcc -D __DEBUG__ test.c

Ausgabe:

__DEBUG__ defined
30
Hossein
quelle
Dies ist ein gutes Beispiel für Definitionen, die wie Boolesche Werte verwendet werden. Das OP fragte jedoch nach String-Definitionen, die schwieriger sind.
Lassi
1

Dies ist meine Lösung für: -DUSB_PRODUCT=\""Arduino Leonardo\""
Ich habe es in einem Makefile verwendet mit:
GNU Make 3.81 (von GnuWin32)
und
avr-g ++ (AVR_8_bit_GNU_Toolchain_3.5.0_1662) 4.9.2

Das Ergebnis in einer vorkompilierten Datei (Option -E für g ++) lautet:
const u8 STRING_PRODUCT[] __attribute__((__progmem__)) = "Arduino Leonardo";

bttcld
quelle
0

Zu Ihrer Information: Anscheinend können sogar verschiedene Versionen derselben Toolchain auf demselben System in dieser Hinsicht unterschiedlich wirken ... (Wie in scheint es, dass dies ein Shell-Passing-Problem ist, aber anscheinend ist es nicht nur auf die Shell beschränkt).

Hier haben wir xc32-gcc 4.8.3 vs. (avr-) gcc 4.7.2 (und mehrere andere), die dasselbe Makefile und main.c verwenden, der einzige Unterschied ist 'make CC=xc32-gcc'usw.

CFLAGS += -D'THING="$(THINGDIR)/thing.h"'wurde über mehrere Jahre in vielen Versionen von gcc (und bash) verwendet.

Um dies mit xc32-gcc kompatibel zu machen (und angesichts eines anderen Kommentars, der behauptet, "ist portabler als"), musste Folgendes getan werden:

CFLAGS += -DTHING=\"$(THINGDIR)/thing.h\"

ifeq "$(CC)" "xc32-gcc"
CFLAGS := $(subst \",\\\",$(CFLAGS))
endif

um die Dinge wirklich verwirrend zu machen, wenn man dies entdeckt: Anscheinend führt ein nicht zitiertes -D mit einem // zu einem #define mit einem Kommentar am Ende ... z

THINGDIR=/thingDir/-> #define /thingDir//thing.h->#define /thingDir

(Danke für die Hilfe von Antwort s hier, btw).

ewh
quelle
0

Ich habe gerade festgestellt, dass eine unserer Anwendungen unter Ubuntu nicht kompiliert werden kann. Und da sich Linux und Windows nicht auf einen gemeinsamen Ansatz geeinigt haben, habe ich diesen verwendet:

NAME := "Mary"

ifeq ($(SystemRoot),)
    # building on another OS
    CFLAGS_ADD += -Dname=\"Mary\"
else
    # building on Windows
    CFLAGS_ADD += -Dname=\\\"Mary\\\"
endif
George Valkov
quelle