我想在 header 文件中放入一个恒定的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的答案也很好,它使我大开眼界。
答案 0 :(得分: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生成难看的头文件。