¿Cómo definir un literal de cadena en la línea de comando gcc?
80
En la línea de comandos de gcc, quiero definir una cadena como -Dname=Mary, luego en el código fuente que quiero printf("%s", name);imprimir Mary.
¿Cómo podría hacerlo?
muchas gracias Arthur. debe ser un experto en C. pregunta adicional: prefiero la segunda opción. cuando estoy usando STRINGIZE_VALUE_OF (nombre), lo traduzco a "1", en el caso de que tenga gcc -Dname = Mary -DMary. ¿Hay alguna forma de dejar que gcc detenga a Interprite Mary?
Richard
Richard, después de mucha revisión, no creo que pueda encontrar una forma que funcione en el ejemplo anterior. Desafortunadamente, sus opciones son sin expansión (por ejemplo, le da "nombre") y expansión completa (por ejemplo, nombre-> María-> 1 si María se define como 1). Dependiendo de su caso de uso exacto, puede haber formas de evitar esto, si Mary puede convertirse en un int const en lugar de un define, por ejemplo.
Arthur Shipkowski
¿Alguien puede explicar por qué necesita usar macros de encadenamiento anidado como ese? Parece que el resultado debería ser el mismo, pero llamar a STRINGIZE_VALUE_OF () parece forzar la expansión macro del argumento, mientras que STRINGIZE () no.
Ionoclast Brigham
1
@IonoclastBrigham, no vi esto hasta hoy. Parte de esto es que a veces desea encadenar palabras desnudas; por ejemplo, en muchos casos se usa stringize para implementar assert () de modo que pueda imprimir la expresión exacta que tiene, en cuyo caso desea tener macros sin expandir. Una vez que se da cuenta de que una cadena de base funciona de esa manera, el anidamiento fuerza una segunda ronda de expansión macro.
Arthur Shipkowski
29
para evitar que la cáscara "se coma" las comillas y otros caracteres, puede probar con comillas simples, como esta:
gcc -o test test.cpp -DNAME='"Mary"'
De esta forma tienes el control total de lo que se define (comillas, espacios, caracteres especiales y todo).
La forma más portátil que encontré hasta ahora es usar \"Mary\": funcionará no solo con gcc sino con cualquier otro compilador de C. Por ejemplo, si intenta utilizarlo /Dname='"Mary"'con el compilador de Microsoft, se detendrá con un error, pero /Dname=\"Mary\"funcionará.
En Ubuntu estaba usando un alias que define CFLAGS, y CFLAGS incluía una macro que define una cadena, y luego uso CFLAGS en un Makefile. Tuve que escapar de los caracteres de comillas dobles y también de los caracteres \. Se veía algo como esto:
A veces, tanto el escape simple como el ajuste entre comillas simples no funcionaban, pero esto sí. Otras veces, no fue así. Creo que la diferencia es si los indicadores se ponen entre comillas en general: 1) DEFINES=-DLOGPATH=\"./logfile\" CFLAGS = -v $(DEFINES)....2) DEFINES=-DLOGPATH=\\\"./logfile\\\" CFLAGS = "-v $(DEFINES)...." usar la opción del compilador -v es útil para ver lo que está haciendo el preprocesador.
Den-Jason
2
Aquí hay un ejemplo simple:
#include<stdio.h>#define A B+20 #define B 10intmain(){
#ifdef __DEBUG__printf("__DEBUG__ DEFINED\n");
printf("%d\n",A);
#elseprintf("__DEBUG__ not defined\n");
printf("%d\n",B);
#endifreturn0;
}
Este es un buen ejemplo de definiciones que se utilizan como booleanos. Sin embargo, el OP preguntó sobre las definiciones de cadena que son más complicadas.
Lassi
1
Esta es mi solución para: -DUSB_PRODUCT=\""Arduino Leonardo\""
Lo usé en un archivo MAKE con:
GNU Make 3.81 (de GnuWin32)
y
avr-g ++ (AVR_8_bit_GNU_Toolchain_3.5.0_1662) 4.9.2
Los resultados en un archivo precompilado (opción -E para g ++) son: const u8 STRING_PRODUCT[] __attribute__((__progmem__)) = "Arduino Leonardo";
FYI: Aparentemente, incluso diferentes versiones de la misma cadena de herramientas en el mismo sistema pueden actuar de manera diferente en este sentido ... (Como en, parecería que esto sería un problema de paso de shell, pero aparentemente no se limita simplemente al shell).
Aquí tenemos xc32-gcc 4.8.3 vs. (avr-) gcc 4.7.2 (y varios otros) usando el mismo makefile y main.c, siendo la única diferencia 'make CC=xc32-gcc', etc.
CFLAGS += -D'THING="$(THINGDIR)/thing.h"'ha estado en uso en muchas versiones de gcc (y bash) durante varios años.
Para hacer esto compatible con xc32-gcc (y a la luz de otro comentario que afirma que \ "es más portátil que '"), se tuvo que hacer lo siguiente:
para hacer las cosas realmente confusas al descubrir esto: aparentemente una -D sin comillas con un // da como resultado un #define con un comentario al final ... ej.
Acabo de descubrir que una de nuestras aplicaciones no se compila en Ubuntu. Y dado que Linux y Windows no estaban de acuerdo en un enfoque común, usé esto:
NAME := "Mary"
ifeq ($(SystemRoot),)
# building on another OS
CFLAGS_ADD += -Dname=\"Mary\"
else# building on Windows
CFLAGS_ADD += -Dname=\\\"Mary\\\"
endif
Me funcionó para VS Code tanto en Mac como en Windows. Otros métodos descritos aquí me gustaron "-Dname=\"SHERAJ\""y "-Dname=\\\"SHERAJ\\\""no funcionaron para mí.
-DNAME=\"Mary\"
) para los tokens que va a definir de esta manera, para que se vean como otras macros.Respuestas:
Dos opciones. Primero, evite las comillas para que la cáscara no se las coma:
O, si realmente quiere -Dname = Mary, puede encadenarlo, aunque es un poco hacky.
#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)); }
Tenga en cuenta que STRINGIZE_VALUE_OF evaluará felizmente hasta la definición final de una macro.
fuente
para evitar que la cáscara "se coma" las comillas y otros caracteres, puede probar con comillas simples, como esta:
gcc -o test test.cpp -DNAME='"Mary"'
De esta forma tienes el control total de lo que se define (comillas, espacios, caracteres especiales y todo).
fuente
La forma más portátil que encontré hasta ahora es usar
\"Mary\"
: funcionará no solo con gcc sino con cualquier otro compilador de C. Por ejemplo, si intenta utilizarlo/Dname='"Mary"'
con el compilador de Microsoft, se detendrá con un error, pero/Dname=\"Mary\"
funcionará.fuente
En Ubuntu estaba usando un alias que define CFLAGS, y CFLAGS incluía una macro que define una cadena, y luego uso CFLAGS en un Makefile. Tuve que escapar de los caracteres de comillas dobles y también de los caracteres \. Se veía algo como esto:
CFLAGS='" -DMYPATH=\\\"/home/root\\\" "'
fuente
1) DEFINES=-DLOGPATH=\"./logfile\" CFLAGS = -v $(DEFINES)....
2) DEFINES=-DLOGPATH=\\\"./logfile\\\" CFLAGS = "-v $(DEFINES)...."
usar la opción del compilador -v es útil para ver lo que está haciendo el preprocesador.Aquí hay un ejemplo simple:
#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; }
Si compilo:
$gcc test.c
Salida:
__DEBUG__ not defined 10
Si compilo:
$gcc -D __DEBUG__ test.c
Salida:
__DEBUG__ defined 30
fuente
Esta es mi solución para:
-DUSB_PRODUCT=\""Arduino Leonardo\""
Lo usé en un archivo MAKE con:
GNU Make 3.81 (de GnuWin32)
y
avr-g ++ (AVR_8_bit_GNU_Toolchain_3.5.0_1662) 4.9.2
Los resultados en un archivo precompilado (opción -E para g ++) son:
const u8 STRING_PRODUCT[] __attribute__((__progmem__)) = "Arduino Leonardo";
fuente
FYI: Aparentemente, incluso diferentes versiones de la misma cadena de herramientas en el mismo sistema pueden actuar de manera diferente en este sentido ... (Como en, parecería que esto sería un problema de paso de shell, pero aparentemente no se limita simplemente al shell).
Aquí tenemos xc32-gcc 4.8.3 vs. (avr-) gcc 4.7.2 (y varios otros) usando el mismo makefile y main.c, siendo la única diferencia
'make CC=xc32-gcc'
, etc.CFLAGS += -D'THING="$(THINGDIR)/thing.h"'
ha estado en uso en muchas versiones de gcc (y bash) durante varios años.Para hacer esto compatible con xc32-gcc (y a la luz de otro comentario que afirma que \ "es más portátil que '"), se tuvo que hacer lo siguiente:
CFLAGS += -DTHING=\"$(THINGDIR)/thing.h\" ifeq "$(CC)" "xc32-gcc" CFLAGS := $(subst \",\\\",$(CFLAGS)) endif
para hacer las cosas realmente confusas al descubrir esto: aparentemente una -D sin comillas con un // da como resultado un #define con un comentario al final ... ej.
THINGDIR=/thingDir/
->#define /thingDir//thing.h
->#define /thingDir
(Gracias por la ayuda de la respuesta es aquí, por cierto).
fuente
Acabo de descubrir que una de nuestras aplicaciones no se compila en Ubuntu. Y dado que Linux y Windows no estaban de acuerdo en un enfoque común, usé esto:
NAME := "Mary" ifeq ($(SystemRoot),) # building on another OS CFLAGS_ADD += -Dname=\"Mary\" else # building on Windows CFLAGS_ADD += -Dname=\\\"Mary\\\" endif
fuente
{ "version": "2.0.0", "tasks": [ { "type": "cppbuild", "label": "C/C++: g++.exe build active file", "command": "C:\\Program Files\\mingw-w64\\x86_64-8.1.0-posix-seh-rt_v6-rev0\\mingw64\\bin\\g++.exe", "args": [ "-g", "-DSHERAJ", "${file}", "-o", "${fileDirname}\\${fileBasenameNoExtension}.exe" ], "options": { "cwd": "C:\\Program Files\\mingw-w64\\x86_64-8.1.0-posix-seh-rt_v6-rev0\\mingw64\\bin" }, "problemMatcher": [ "$gcc" ], "group": { "kind": "build", "isDefault": true }, "detail": "compiler: \"C:\\Program Files\\mingw-w64\\x86_64-8.1.0-posix-seh-rt_v6-rev0\\mingw64\\bin\\g++.exe\"" } ] }
Lo he hecho
#define SHERAJ
aquí en VS Code. Funciona muy bien para la programación competitiva como:int main() { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); #ifdef SHERAJ freopen("input.txt" , "r", stdin); #endif int T; cin>>T; for(int test_case = 1;test_case<=T;test_case++) { cout<<"Hello World"<<endl; } }
Me funcionó para VS Code tanto en Mac como en Windows. Otros métodos descritos aquí me gustaron
"-Dname=\"SHERAJ\""
y"-Dname=\\\"SHERAJ\\\""
no funcionaron para mí.Entonces la respuesta es
"-DSHERAJ"
fuente