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?

2

9 Answers 9

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.

5
  • 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 9, 2010 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. Mar 10, 2010 at 2: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. Mar 13, 2014 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. Nov 9, 2014 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 7, 2022 at 8: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).

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.

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\\\" "'
1
  • 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, 2017 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";

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
1
  • 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 6, 2019 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).

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
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".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.