gcc是否支持宏定义中的多行原始字符串文字?

问题描述 投票:1回答:1

我想在头文件中放置一个常量的json字符串,以便可以使用它,也可以被其他源查看。我想在C ++ 11中使用原始字符串文字,因为它看起来很清晰漂亮。但是,我已经尝试了使用gcc -std=c++11 test.cpp编译以下代码的gcc 4.8.5 / gcc 4.9.2:

#include <cstdio>

/* works, but looks ugly */
#define STR_a \
"{ \n\
    \"AAA\": \"a\", \n\
    \"BBB\": \"b\" \n\
}"

/* works with VS2017, not works with gcc */
#define STR_b \
R"({
    "AAA": "a",
    "BBB": "b"
})";

/* works, but must use 'extern const'/'static' in header files */
const char *STR_var = 1 + R"(
{
    "AAA": "a",
    "BBB": "b"
})";

int main()
{
    const char *s = STR_b;
    printf("%s\n", s);
    return 0;
}

但是,我得到编译错误:

   

test.cpp:16:1: error: unterminated raw string
 R"({ 
 ^
test.cpp:19:3: warning: missing terminating " character
 })";
   ^
test.cpp:19:1: error: missing terminating " character
 })";
 ^
test.cpp:29:2: error: stray ‘R’ in program

如果我添加反斜杠,gcc工作:

#define STR_b \
R"({ \
    "AAA": "a", \
    "BBB": "b" \
})";

但它显示错误的字符串:

{ \
    "AAA": "a", \
    "BBB": "b" \
}

它是实现定义的功能吗?更高版本的gcc是否支持此功能?


编辑:

我下载并编译了gcc 7.3.1源代码,然后再次尝试我的测试代码;但是,gcc7.3.1报告了与gcc 4.X相同的错误。我放弃了,并决定继续使用static const char *。 @lyang的答案也很好,它开启了我的思想。

c++ c++11 gcc g++
1个回答
0
投票

最新更新4/4/2019

我最近听说过Cog并认为它可能是比m4更好的解决方案。它使用python进行预处理,使代码更易读,如下所示(轻松支持字符串内的引用):

#include <cstdio>

/*[[[cog
import cog, re

def escape_raw(s):
    s = re.sub(r'\\', r'\\\\', s) # escape backslash first
    s = re.sub(r'"', r'\"', s) # escape quotes
    return re.sub(r'\n', r'\\n\n', s) # escape newline last

def cog_define(name, val):
    cog.outl("#define {name} {val}".format(name=name, val=val))

STR_test = r"""{
    "AAA": "a",
    "BBB": "b",
    "contain \" quote": "c"
}"""

cog_define("STR_test", escape_raw(STR_test))

]]]*/
//[[[end]]]

int main()
{
    const char *s = STR_test;
    printf("%s\n", s);
    return 0;
}

输出:

#include <cstdio>

/*[[[cog
import cog, re

def escape_raw(s):
    s = re.sub(r'\\', r'\\\\', s) # escape backslash first
    s = re.sub(r'"', r'\"', s) # escape quotes
    return re.sub(r'\n', r'\\n\n', s) # escape newline last

def cog_define(name, val):
    cog.outl("#define {name} {val}".format(name=name, val=val))

STR_test = r"""{
    "AAA": "a",
    "BBB": "b",
    "contain \" quote": "c"
}"""

cog_define("STR_test", escape_raw(STR_test))

]]]*/
#define STR_test {\n
    \"AAA\": \"a\",\n
    \"BBB\": \"b\",\n
    \"contain \\\" quote\": \"c\"\n
}
//[[[end]]]

int main()
{
    const char *s = STR_test;
    printf("%s\n", s);
    return 0;
}

==============================================================

你试过GNU的m4吗?

这有点像hacky,但想法是将一个更好看的版本预处理到丑陋的版本(不使用原始字符串)。

你的代码将是这样的:

#include <cstdio>

m4_changecom(`/*', `*/')
m4_define(`ESCAPE_RAW', `"m4_patsubst(`m4_patsubst($1, `"', `\\"')', `
', `\\n\\
')'") /* substitute newline and double quote with escaped version */

#define STR_test ESCAPE_RAW(`{
    "AAA": "a",
    "BBB": "b"
}')

int main()
{
    const char *s = STR_test;
    printf("%s\n", s);
    return 0;
}

丑陋的ESCAPE_RAW宏只需要定义一次,所有后面的“原始字符串”都可以使用ESCAPE_RAW生成gcc识别的丑陋版本。

要使用m4进行预处理,请使用命令m4 -P test.cpp,其中-P强制在define语句中使用m4_前缀。该命令产生:

#include <cstdio>




#define STR_test "{\n\
    \"AAA\": \"a\",\n\
    \"BBB\": \"b\"\n\
}"

int main()
{
    const char *s = STR_test;
    printf("%s\n", s);
    return 0;
}

也许用.m4扩展名命名你的m4文件,并使用m4生成丑陋的头文件。

© www.soinside.com 2019 - 2024. All rights reserved.