我想在头文件中放置一个常量的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的答案也很好,它开启了我的思想。
最新更新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生成丑陋的头文件。