Как определить строковый литерал в командной строке gcc?


80

В командной строке gcc я хочу определить строку, например -Dname=Mary, затем в исходном коде, который я хочу printf("%s", name);напечатать Mary.
Как я мог это сделать?


8
Я настоятельно рекомендую вам использовать all-caps ( -DNAME=\"Mary\") для токенов, которые вы собираетесь определить таким образом, чтобы они выглядели как другие макросы.
— JSB ձոգչ

Ответы:


97

Два варианта. Во-первых, избегайте кавычек, чтобы оболочка их не съела:

gcc -Dname=\"Mary\"

Или, если вы действительно хотите -Dname = Mary, вы можете преобразовать его в строку, хотя это немного взломано.

#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));
}

Обратите внимание, что STRINGIZE_VALUE_OF с радостью выполнит оценку вплоть до окончательного определения макроса.


Большое спасибо, Артур. вы должны быть экспертом в C. дальнейший вопрос: я предпочитаю второй вариант. когда я использую STRINGIZE_VALUE_OF (имя), он переводит его в «1», в случае, если у меня есть gcc -Dname = Mary -DMary. есть в любом случае , чтобы остановить GCC interprite Мэри
— ричард

Ричард, после долгих обзоров я не верю, что смогу придумать способ, который работает в приведенном выше примере. К сожалению, вы можете выбрать не расширение (например, дает вам «имя») или полное раскрытие (например, имя-> Мэри-> 1, если Мэри определена как 1). В зависимости от вашего конкретного случая использования могут быть способы обойти это - например, если Мэри может стать const int, а не определением.
— Артур Шипковски

Может ли кто-нибудь объяснить, почему вам нужно использовать такие вложенные макросы стрингификации? Кажется, что результат должен быть таким же, но вызов STRINGIZE_VALUE_OF (), похоже, заставляет макрос раскрыть аргумент, а STRINGIZE () - нет.
— Ionoclast Brigham

1
@IonoclastBrigham, не видел этого до сегодняшнего дня. Частично это связано с тем, что иногда вы хотите структурировать голые слова - например, во многих случаях stringize используется для реализации assert (), чтобы он мог распечатать точное выражение, которое у вас есть - и в этом случае вы хотите, чтобы макросы были нерасширенными. Как только вы поймете, что базовая строка работает таким образом, вложение вызывает второй раунд макрорасширения.
— Артур Шипковски

29

чтобы оболочка не «съедала» кавычки и другие символы, вы можете попробовать одинарные кавычки, например:

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

Таким образом, у вас есть полный контроль над тем, что определяется (кавычки, пробелы, специальные символы и все остальное).


8

Самый переносимый способ, который я нашел до сих пор, - это использовать \"Mary\"- он будет работать не только с gcc, но и с любым другим компилятором C. Например, если вы попытаетесь использовать /Dname='"Mary"'компилятор Microsoft, он остановится с ошибкой, но /Dname=\"Mary\"будет работать.


6

В Ubuntu я использовал псевдоним, определяющий CFLAGS, а CFLAGS включал макрос, который определяет строку, а затем я использую CFLAGS в Makefile. Мне пришлось избегать символов двойных кавычек, а также символов \. Выглядело это примерно так:

CFLAGS='" -DMYPATH=\\\"/home/root\\\" "'

2
Иногда как одиночное экранирование, так и перенос в одинарные кавычки не работали, но это сработало. В других случаях это не так. Я думаю, разница заключается в том, заключены ли флаги в кавычки: 1) DEFINES=-DLOGPATH=\"./logfile\" CFLAGS = -v $(DEFINES).... 2) DEFINES=-DLOGPATH=\\\"./logfile\\\" CFLAGS = "-v $(DEFINES)...." использование параметра компилятора -v полезно, чтобы увидеть, что делает препроцессор.
— Ден-Джейсон

2

Вот простой пример:

#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;
}

Если я компилирую:

$gcc test.c

Вывод:

__DEBUG__ not defined
10

Если я компилирую:

$gcc -D __DEBUG__ test.c

Вывод:

__DEBUG__ defined
30

Это хороший пример определений, которые используются как логические. Однако OP спросил о строковых определениях, которые более сложны.
— Lassi

1

Это мое решение для: -DUSB_PRODUCT=\""Arduino Leonardo\""
Я использовал его в make-файле с:
GNU Make 3.81 (из GnuWin32)
и
avr-g ++ (AVR_8_bit_GNU_Toolchain_3.5.0_1662) 4.9.2

Результаты в предварительно скомпилированном файле (опция -E для g ++):
const u8 STRING_PRODUCT[] __attribute__((__progmem__)) = "Arduino Leonardo";


0

К вашему сведению: очевидно, что даже разные версии одной и той же инструментальной цепочки в одной и той же системе могут действовать по-разному в этом отношении ... (Как и в случае, казалось бы , это проблема передачи оболочки, но, очевидно, она не ограничивается только оболочкой).

Здесь у нас xc32-gcc 4.8.3 vs. (avr-) gcc 4.7.2 (и несколько других) с использованием того же make-файла и main.c, единственная разница в том 'make CC=xc32-gcc'и т. Д.

CFLAGS += -D'THING="$(THINGDIR)/thing.h"'использовался на многих несколько лет версиях gcc (и bash).

Чтобы сделать это совместимым с xc32-gcc (и в свете другого комментария, утверждающего, что \ "более переносимо, чем '"), необходимо было сделать следующее:

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

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

чтобы сделать вещи действительно запутанными при обнаружении этого: очевидно, что -D без кавычек с // приводит к #define с комментарием в конце ... например,

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

(Спасибо за помощь ответа S здесь, кстати).


0

Я только что обнаружил, что одно из наших приложений не компилируется на Ubuntu. И поскольку Linux и Windows не пришли к единому подходу, я использовал это:

NAME := "Mary"

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

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\""
        }
    ]
}

Я сделал это #define SHERAJздесь, в VS Code. Он отлично подходит для соревновательного программирования, так как -

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;
    }
}

У меня это сработало для VS Code как на Mac, так и на Windows. Остальные методы, описанные здесь, мне понравились "-Dname=\"SHERAJ\""и "-Dname=\\\"SHERAJ\\\""не работали.

Итак, ответ "-DSHERAJ"

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.