我不幸的是今天做了一些代码考古(虽然重构了一些旧的危险代码)并发现了一个像这样的小化石:
# line 7 "foo.y"
我完全惊讶地发现那里有如此古老的宝藏。我在一个C编程网站上读到了它。然而,它没有解释为什么有人想要使用它。因此我不得不猜测程序员纯粹是为了向编译器说谎而感到非常高兴。
注意: (请注意,化石实际上是在cpp文件的第3行)(哦,该文件确实指向了与该文件几乎完全相同的.y文件。
有谁知道为什么需要这样的指令?或者它可以用于什么?
答案 0 :(得分:17)
自动代码生成工具(如yacc
或bison
)通常使用它来将行号设置为实际源文件中行的值,而不是C
源文件。
这样,当您收到错误消息时说:
a += xyz;
^ No such identifier 'xyz' on line 15 of foo.y
您可以查看实际源文件的第15行以查看问题。
否则,它会说像No such identifier 'xyz' on line 1723 of foo.c
这样荒谬的东西,你必须手动将自动生成的C
文件中的那一行与真实文件中的等效项相关联。相信我,除非你想深入参与词汇和语义分析的内部(或者你想要大脑出血),否则你不想浏览yacc
生成的代码(bison
可能会产生更好的代码,我不知道,但我也不在乎,因为我写了更高级别的代码。)
根据C99标准,它有两种形式:
#line 12345
#line 12345 "foo.y"
第一个只设置报告的行号,第二个也会更改报告的文件名,因此您可以在foo.y
的第27行而不是foo.c
中收到错误。
至于“程序员纯粹是为了向编译器说谎的纯粹快乐”,没有。我们可能会弯曲和扭曲,但我们通常不会恶意:-)这条线被yacc
或bison
本身放在那里为你帮忙。
答案 1 :(得分:5)
我看到这个功能唯一有用的地方是生成代码。如果您使用的工具从另一个表单中定义的源生成C文件,则在单独的文件中(即:“。y”文件),使用#line
可以帮助用户知道“真实”的位置问题是,他们应该去哪里纠正它(他们放原始代码的.y文件)。
答案 2 :(得分:2)
#line指令的目的主要是供工具使用 - 代码生成器可以使用它,以便调试器(例如)可以保留用户代码中的内容的上下文,因此错误消息可以将用户引用到在他的源文件中的位置。
我从来没有见过程序员手动使用它的指令 - 而且我不确定它会有多大用处。
答案 3 :(得分:2)
它有更深层次的目的。原始C预处理器是与编译器分开的程序。在将几个.h文件合并到.c文件之后,人们仍然想知道错误消息来自stdio.h的第42行或main.c的第17行。如果没有某种通信方式,编译器将无法知道哪个源文件最初持有违规行代码。
它还影响任何源级调试器在生成的代码和源文件与行号之间进行转换所需的表。
当然,在这种情况下,您正在查看由工具(可能名为yacc或bison)编写的文件,该工具用于根据语法描述创建解析器。该文件实际上不是源文件。它是从真实的源文本创建的。
如果您的考古学引导您解决问题,那么您将需要确定实际使用的解析器生成器,并对解析器进行一些背景阅读,这样您就可以理解为什么它在这样做了所有。 yacc,bison或其他工具的文档可能也会有所帮助。
答案 4 :(得分:1)
我已经使用#line和#error创建了一个你编译的临时* .c文件,让你的IDE为你提供一个可浏览的一些第三方工具发现的错误列表。
例如,我将输出文件从PC-LINT传送到perl脚本,该脚本将人类可读错误转换为#line和#error行。然后编译了这个输出,我的IDE让我使用F4逐步完成每个错误。手动打开每个文件并跳转到特定行的速度要快得多。