8

AFAIK,这个问题同样适用于C和 C++

C标准(草案 C99 标准中的 5.1.1.2)中指定的“翻译阶段”的第 6 步规定必须将相邻的字符串文字连接成单个文字。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让它它假设在它之前运行。

4

5 回答 5

9

该标准没有指定预处理器与编译器,它只是指定了您已经注意到的翻译阶段。传统上,第 1 到第 4 阶段在预处理器中,第 5 到第 7 阶段在编译器中,第 8 阶段在链接器中——但标准都不需要这些。

于 2010-06-29T16:27:07.557 回答
4

除非指定预处理器来处理这个问题,否则可以安全地假设它是编译器的工作。

编辑:

您在帖子开头的“ Ie ”链接回答了这个问题:

相邻的字符串文字在编译时连接;这允许将长字符串拆分为多行,还允许在编译时将由 C 预处理器定义和宏生成的字符串文字附加到字符串...

于 2010-06-29T16:22:43.620 回答
2

在 ANSI C 标准中,此详细信息在第 5.1.1.2 节第 (6) 项中进行了介绍:

5.1.1.2 翻译阶段
...

4. 执行预处理指令并扩展宏调用。...

5. 字符常量和字符串文字中的每个源字符集成员和转义序列都被转换为执行字符集的成员。

6. 连接相邻的字符串文字标记,连接相邻的宽字符串文字标记。

该标准本身并未定义实现必须使用预处理器和编译器。

第 4 步显然是预处理器的职责。

第 5 步要求知道“执行字符集”。编译器也需要此信息。如果预处理器不包含平台依赖性,则将编译器移植到新平台会更容易,因此倾向于在​​编译器中实现步骤 5,从而实现步骤 6。

于 2010-06-29T16:29:57.983 回答
1

我会在解析器的扫描令牌部分处理它,所以在编译器中。这似乎更符合逻辑。预处理器不必知道语言的“结构”,实际上它通常会忽略它,以便宏可以生成不可编译的代码。它只处理专门针对它的指令有权处理的内容# ...#define x h

于 2010-07-05T20:37:15.147 回答
1

字符串文字连接如何与转义序列交互有一些棘手的规则。假设你有

const char x1[] = "a\15" "4";
const char y1[] = "a\154";
const char x2[] = "a\r4";
const char y2[] = "al";

那么x1x2必须根据 和 等于和和strcmp相同。(这就是 Heath 在引用翻译步骤时的意思 - 转义转换发生字符串常量连接之前。)还有一个要求,如果连接组中的任何字符串常量有一个or前缀,你会得到一个宽或 Unicode 字符串. 将它们放在一起,作为“编译器”而不是“预处理器”的一部分来完成这项工作会更加方便。 y1y2LU

于 2010-07-16T18:00:00.373 回答