¿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?

Ricardo
fuente
8
Le recomiendo que use mayúsculas ( -DNAME=\"Mary\") para los tokens que va a definir de esta manera, para que se vean como otras macros.
JSB ձոգչ
La macro en cuestión de cadena: stackoverflow.com/questions/240353/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

97

Dos opciones. Primero, evite las comillas para que la cáscara no se las coma:

gcc -Dname=\"Mary\"

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.

Arthur Shipkowski
fuente
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).

Johann
fuente
8

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á.

psihodelia
fuente
6

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\\\" "'
Samuel
fuente
2
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 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
Hossein
fuente
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";

bttcld
fuente
0

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).

ewh
fuente
0

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
George Valkov
fuente
0
{
    "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 SHERAJaquí 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"

Mohammad Sheraj
fuente