为了简化在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。
答案 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 ++中的语法生成与''
不匹配。此序列不能出现在更大的事物之外的符合程序中(如字符串文字)。
宏进程在字符级别上不起作用,毕竟它在令牌级别上工作。一切都需要先被标记化。