如何在gcc命令行中定义字符串文字?


79

在gcc命令行中,我想定义一个字符串,例如-Dname=Mary,然后在源代码中我要printf("%s", name);打印Mary
我该怎么办?


7
我强烈建议您将全大写字母(-DNAME=\"Mary\")用于将要以这种方式定义的令牌,以使它们看起来像其他宏。
JSBձոգչ2010年

Answers:


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语言方面的专家。进一步的问题:我推荐第二种选择。当我使用gcc -Dname = Mary -DMary时,当我使用STRINGIZE_VALUE_OF(name)时,它将转换为“ 1”。无论如何,有什么办法让gcc停止插入玛丽
理查德(Richard)2010年

理查德(Richard),经过大量的回顾,我认为我无法在以上示例中找到可行的方法。不幸的是,您的选择是没有扩展名(例如,给您“名称”)和完全扩展名(例如,如果Mary被定义为1,则为name-> Mary-> 1)。根据您的实际使用情况,可能有一些解决方法-例如,如果Mary可以成为const int而不是define。
Arthur Shipkowski 2010年

谁能为您为什么需要使用嵌套的字符串化宏提供理由?看起来结果应该是相同的,但是调用STRINGIZE_VALUE_OF()似乎会强制参数的宏扩展,而STRINGIZE()不会。
Ionoclast Brigham 2014年

1
@IonoclastBrigham,直到今天才看到。部分原因在于,有时您希望对裸字进行字符串化-例如,在许多情况下,字符串化用于实现assert(),以便可以打印出您所拥有的确切表达式-在这种情况下,您希望宏不展开。一旦意识到以这种方式实现基本的字符串化,嵌套便会强制进行第二轮宏扩展。
Arthur Shipkowski 2014年

29

为了避免外壳“吃掉”引号和其他字符,您可以尝试使用单引号,如下所示:

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

这样,您就可以完全控制定义的内容(引号,空格,特殊字符和全部)。


8

到目前为止,我发现的最可移植的方式是使用\"Mary\"-它不仅适用于gcc,而且适用于任何其他C编译器。例如,如果您尝试/Dname='"Mary"'与Microsoft编译器一起使用,它将停止并显示错误,但/Dname=\"Mary\"可以使用。


6

在Ubuntu中,我使用了一个定义CFLAGS的别名,CFLAGS包含了一个定义字符串的宏,然后在Makefile中使用CFLAGS。我必须转义双引号和\字符。它看起来像这样:

CFLAGS='" -DMYPATH=\\\"/home/root\\\" "'

2
有时候,单引号和单引号都没有用,但是这样做了。其他时候没有。我认为区别在于标志是否整体放在引号中:1) DEFINES=-DLOGPATH=\"./logfile\" CFLAGS = -v $(DEFINES).... 2) DEFINES=-DLOGPATH=\\\"./logfile\\\" CFLAGS = "-v $(DEFINES)...." 使用-v编译器选项对查看预处理器的工作很有用。
Den-Jason

3

这是一个简单的示例:

#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\""
我在以下文件中使用它:
GNU Make 3.81(来自GnuWin32)

avr-g ++(AVR_8_bit_GNU_Toolchain_3.5.0_1662)4.9.2

预编译文件中的结果(对于g ++,为-E选项)为:
const u8 STRING_PRODUCT[] __attribute__((__progmem__)) = "Arduino Leonardo";


0

仅供参考:显然,即使在同一系统上,同一工具链的不同版本在这方面也可以发挥不同的作用……(例如,这似乎是一个绕过shell的问题,但显然不仅限于shell)。

在这里,我们使用相同的makefile和main.c来实现xc32-gcc 4.8.3与(avr-)gcc 4.7.2(以及其他几个),唯一的区别是'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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.