106

On the GCC command line, I want to define a string such as -Dname=Mary. Then in the source code, I want printf("%s", name); to print Mary.

How could I do it?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
richard
  • 1,607
  • 6
  • 15
  • 18

9 Answers9

118

Two options. First, escape the quotation marks so the shell doesn't eat them:

gcc -Dname=\"Mary\"

Or, if you really want -Dname=Mary, you can stringize it, though it's a bit 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));
}

Note that STRINGIZE_VALUE_OF will happily evaluate down to the final definition of a macro.

Arthur Shipkowski
  • 3,606
  • 1
  • 22
  • 30
  • thank you so much Arthur. you must be a expert in C. further question: I perfer the second option. when I'm using STRINGIZE_VALUE_OF(name), it translate it to "1", in the case that I have gcc -Dname=Mary -DMary. is there anyway to let gcc stop interprite Mary – richard Mar 09 '10 at 19:24
  • Richard, after much review I do not believe I can come up with a way that works in the above example. Unfortunately, your choices are no expansion (e.g. gives you "name") and full expansion (e.g. name->Mary->1 if Mary is defined as 1). Depending on your exact usage case there may be ways around this -- if Mary can become a const int rather than a define, for example. – Arthur Shipkowski Mar 10 '10 at 02:53
  • Can anyone give a rationale for why you need to use nested stringification macros like that? It seems like the result should be the same, but calling STRINGIZE_VALUE_OF() seems to force macro expansion of the argument, while STRINGIZE() doesn't. – Ionoclast Brigham Mar 13 '14 at 23:52
  • 1
    @IonoclastBrigham, didn't see this until today. Part of this is that sometimes you want to stringize barewords -- for example, in many cases stringize is used to implement assert() such that it can print out the exact expression you have -- in which case you want to have macros unexpanded. Once you realize a base stringize works that way, the nesting forces a second round of macro expansion. – Arthur Shipkowski Nov 09 '14 at 23:57
  • The 2nd option is the way to go if you can't pass [double quote] as parameter. In my case, I've gitlab CI calling powershell calling a .exe compiled from eclipse (java). So many interpretations before calling gcc, so it is easier to handle it in the C code at the end. – ofaurax Sep 07 '22 at 08:52
34

To avoid the shell "eating" the quotes and other characters, you might try single quotes, like this:

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

This way you have full control what is defined (quotes, spaces, special characters, and all).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John
  • 1,709
  • 1
  • 24
  • 27
10

The most portable way I found so far was to use \"Mary\". It will work not only with GCC, but with any other C compiler. For example, if you try to use /Dname='"Mary"' with a Microsoft compiler, it will stop with an error, but /Dname=\"Mary\" will work.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
psihodelia
  • 29,566
  • 35
  • 108
  • 157
8

In Ubuntu I was using an alias that defines CFLAGS, and CFLAGS included a macro that defines a string, and then I use CFLAGS in a Makefile. I had to escape the double quote characters and as well the \ characters. It looked something like this:

CFLAGS='" -DMYPATH=\\\"/home/root\\\" "'
Samuel
  • 8,063
  • 8
  • 45
  • 41
  • 2
    Sometimes, both single escaping and wrapping in single quotes didn't work, but this did. Other times, it didn't. I think the difference is whether the flags are put in quotes overall: `1) DEFINES=-DLOGPATH=\"./logfile\" CFLAGS = -v $(DEFINES)....` `2) DEFINES=-DLOGPATH=\\\"./logfile\\\" CFLAGS = "-v $(DEFINES)...."` Using the -v compiler option is useful to see what the preprocessor is doing. – Den-Jason Dec 15 '17 at 12:13
2

This is my solution for : -DUSB_PRODUCT=\""Arduino Leonardo\""
I used it in a makefile with:
GNU Make 3.81 (from GnuWin32)
and
avr-g++ (AVR_8_bit_GNU_Toolchain_3.5.0_1662) 4.9.2

The results in a precompiled file (-E option for g++) is:
const u8 STRING_PRODUCT[] __attribute__((__progmem__)) = "Arduino Leonardo";

bttcld
  • 31
  • 2
1

Here is a simple example:

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

If I compile:

$gcc test.c

Output:

__DEBUG__ not defined
10

If I compile:

$gcc -D __DEBUG__ test.c

Output:

__DEBUG__ defined
30
Hossein
  • 113
  • 1
  • 6
  • This is a good example of defines that are used like booleans. However the OP asked about string defines which are more tricky. – Lassi Nov 06 '19 at 13:31
0

FYI: Apparently even different versions of the same toolchain on the same system can act differently in this regard... (As in, it would seem this would be a shell-passing issue, but apparently it's not limited to merely the shell).

Here we have xc32-gcc 4.8.3 vs. (avr-)gcc 4.7.2 (and several others) using the same makefile and main.c, the only difference being 'make CC=xc32-gcc', etc.

CFLAGS += -D'THING="$(THINGDIR)/thing.h"' has been in-use on many versions of gcc (and bash) over several years.

In order to make this compatible with xc32-gcc (and in light of another comment claiming that \" is more portable than '"), the following had to be done:

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

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

to make things really confusing in discovering this: apparently an unquoted -D with a // results in a #define with a comment at the end... e.g.

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

(Thanks for the help from answers here, btw).

ewh
  • 41
  • 3
0

I just found that one of our applications does not compile on Ubuntu. And since Linux and Windows didn't agree on a common approach, I used this:

NAME := "Mary"

ifeq ($(SystemRoot),)
    # building on another OS
    CFLAGS_ADD += -Dname=\"Mary\"
else
    # building on Windows
    CFLAGS_ADD += -Dname=\\\"Mary\\\"
endif
George Valkov
  • 1,217
  • 12
  • 10
0

Consider:

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

I have done #define SHERAJ here in Visual Studio Code. It works great for competitive programming as:

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

It worked for me for Visual Studio Code on both Mac and Windows. Other methods described here, like "-Dname=\"SHERAJ\"" and "-Dname=\\\"SHERAJ\\\"" did not work for me.

So the answer is "-DSHERAJ".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zeitgeist
  • 852
  • 12
  • 19