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