Як визначити рядковий літерал у командному рядку 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 зупинити неприховану Мері
Річард

Річарде, після довгих оглядів я не вірю, що можу придумати спосіб, який спрацьовує у наведеному вище прикладі. На жаль, ваш вибір - це не розширення (наприклад, дає вам «ім’я») та повне розширення (наприклад, ім’я-> Мері-> 1, якщо Мері визначено як 1). Залежно від вашого конкретного випадку використання, це можуть бути шляхи - якщо Мері може стати const int, а не дефініцією, наприклад.
Arthur Shipkowski

Хто-небудь може дати обгрунтування, чому вам потрібно використовувати такі вкладені макроси розтягування? Здається, результат повинен бути однаковим, але виклик STRINGIZE_VALUE_OF (), здається, змушує розширити макрос аргументу, тоді як STRINGIZE () - ні.
Іонокласт Брігам

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 запитав про рядок, який є більш хитрим.
Лассі

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

FYI: Очевидно, навіть різні версії одного і того ж ланцюжка інструментів в одній системі можуть діяти по-різному в цьому відношенні ... (Як, здається, це було б проблемою проходження оболонки, але, очевидно, це не обмежується лише оболонкою).

Тут ми маємо xc32-gcc 4.8.3 проти (avr-) gcc 4.7.2 (та декілька інших), використовуючи той самий makefile та 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.