字符串化块中的空字符文字

时间:2014-10-20 13:32:43

标签: c++ clang language-lawyer c-preprocessor c++03

为了简化在C ++中编写SQL查询,我使用宏

#define SQL(...) #__VA_ARGS__

它工作正常,除非出现空字符串文字(类似

SQL(select * from foo where bar = '')

),clang(没有其他编译器)发出警告

warning: empty character constant [-Winvalid-pp-token]

我正在做的是一个严重的黑客攻击(我仍然保留,因为它允许多行sql语句可读)违反标准或者在这里过于关键(字符文字没有出现在预处理器指令中)?

编辑:忘记提及并非所有平台都支持C ++ 11,因此我们无法使用原始字符串文字。我们可能会坚持使用VisualC ++ 9.0多年,而Gcc 4.6-somesnapshot可能更少,但仍然是几年。黑客攻击也早于C ++ 11。

1 个答案:

答案 0 :(得分:5)

你正在做的是一个严重的黑客攻击,如果你正在使用Clang(和其他现代编译器)进行编译但是不需要支持旧的编译器,那么可以采用更简单的方法:原始字符串文字。

std::string query = R"sql(
  select * from foo where bar = ''
)sql";

如果你愿意,这甚至允许你在查询中嵌入引号和反斜杠而不转义。

作为参考,自Clang 3.0,GCC 4.5和Visual Studio 2013以来,支持原始字符串文字。

从语言律师的角度来看,Clang慷慨地允许你的代码编译。它无效。 C ++ 14 2.2表示在第3阶段(宏替换发生在第4阶段),源文件被分解为预处理令牌和空白序列。

2.5列出了预处理令牌语法生成。那里只有一个以单引号开头的选项,即字符文字。字符文字在2.14.3中定义为

character-literal:
    ' c-char-sequence '
    <prefixed versions>

c-char-sequence:
    c-char
    c-char-sequence c-char

c-char:
    any member of the source character set except
        the single-quote ' , backslash \, or new-line character
    escape-sequence
    universal-character-name

请注意,c-char-sequence由至少一个c-char组成,而c-char不能是单引号。因此,C ++中的语法生成与''不匹配。此序列不能出现在更大的事物之外的符合程序中(如字符串文字)。

宏进程在字符级别上不起作用,毕竟它在令牌级别上工作。一切都需要先被标记化。