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

时间:2019-03-12 04:00:02

标签: c++ c++11 gcc g++

我想在 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的答案也很好,它使我大开眼界。

1 个答案:

答案 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生成难看的头文件。