在C和C ++中实现字符串字面串联
-
01-10-2019 - |
题
afaik,这个问题同样适用于 C 和C ++
步骤6的“翻译阶段” C 标准(C99标准草案中的5.1.1.2)指出,必须将相邻的字符串文字串联成单个字面。 IE
printf("helloworld.c" ": %d: Hello "
"world\n", 10);
是等效的(语法上)
printf("helloworld.c: %d: Hello world\n", 10);
但是,该标准似乎并未指定编译器的哪一部分必须处理 - 如果是预处理器(如果是预处理器)(cpp
)或编译器本身。一些在线研究告诉我,通常预计该功能将由预处理器执行(来源#1, 来源#2, ,还有更多),这是有道理的。
但是,运行 cpp
在Linux中表明 cpp
不这样做:
eliben@eliben-desktop:~/test$ cat cpptest.c
int a = 5;
"string 1" "string 2"
"string 3"
eliben@eliben-desktop:~/test$ cpp cpptest.c
# 1 "cpptest.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpptest.c"
int a = 5;
"string 1" "string 2"
"string 3"
因此,我的问题是:在预处理器或编译器本身中,应该在哪里处理该语言的此功能?
也许没有一个好的答案。基于经验,已知编译器和一般良好工程实践的启发式答案将不胜感激。
PS如果您想知道我为什么关心这个...我想弄清楚我的 基于Python的C解析器 应处理字符串字面串联(目前尚未这样做),或将其留给 cpp
它假设在它之前运行。
解决方案
该标准未指定预处理器与编译器,它只是指定您已经注意到的翻译阶段。传统上,第1到4阶段在预处理程序中,虽然在编译器中为7,而第8阶段则是连接器 - 但标准不需要这些。
其他提示
除非指定预处理器来处理此问题,否则可以肯定地假设它是编译器的工作。
编辑:
您的 ”IE“帖子开头的链接回答了一个问题:
相邻的字符串文字在编译时被串联;这使长字符串可以在多行上拆分,还允许字符串文字 由C预处理器定义和宏 附加到字符串 在编译时...
在ANSI C标准中,该细节在第5.1.1.2节中介绍,第(6)项:
5.1.1.2翻译阶段
...
4.执行预处理指令并扩展宏观调节。 ...
5.字符常数和字符串文字中的每个源字符集成员和逃生序列都转换为执行字符集的成员。
6.相邻的字符串字面令牌是串联的,相邻的宽字符串字面令牌是串联的。
该标准并未定义实施本身必须使用预处理器和编译器。
步骤4显然是预处理器的责任。
步骤5要求知道“执行字符集”。编译器也需要此信息。如果预处理器不包含平台依赖性,则将编译器移植到新平台上更容易,因此趋势是在编译器中实现步骤5,因此步骤6。
关于字符串的字面串联如何与逃生序列相互作用有一些棘手的规则。假设你有
const char x1[] = "a\15" "4";
const char y1[] = "a\154";
const char x2[] = "a\r4";
const char y2[] = "al";
然后 x1
和 x2
必须根据 strcmp
, ,也是如此 y1
和 y2
. 。 (这是希思在引用翻译步骤中所获得的 - 逃脱转换发生 前 字符串恒定串联。)也需要 任何 串联组中的字符串常数有一个 L
或者 U
前缀,您会得到一个宽或Unicode字符串。将所有内容放在一起,它可以作为“编译器”而不是“预处理器”的一部分进行这项工作更加方便。
我会在解析器的扫描令牌中处理它,因此在编译器中。似乎更合乎逻辑。预处理器不知道语言的“结构”,实际上它通常会忽略它,以便宏可以生成不可兼容的代码。它无非是由专门解决该指令的指令处理的权利(# ...
),以及它们的“后果”(就像一个 #define x h
, ,这将使预处理器将很多X变为H)