Как определить строковый литерал в командной строке 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.