1

C++ 标准定义well-formed programs

根据语法规则、可诊断语义规则和单定义规则构造的C++程序

我想知道是否所有格式良好的程序都可以编译(如果不是这种情况,什么类型的错误会影响格式正确的程序和可编译问题之间的差异)。例如,包含歧义错误的程序是否会被视为格式正确?

4

2 回答 2

5

一个格式良好的程序可以有未定义的行为。

它在注释中,因此在技术上不具有权威性,但似乎有意终止编译(或标准所称的“翻译”)在可能的 UB 范围内:

[介绍.defs]

未定义的行为

本文档对其没有要求
的行为 [注意:当本文档省略任何明确的行为定义或程序使用错误构造或错误数据时,可能会出现未定义的行为。

允许的未定义行为的范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(有或没有发出诊断消息),到终止翻译或执行(发出的诊断消息)。

许多错误的程序结构不会产生未定义的行为;他们需要被诊断出来。

常量表达式的求值永远不会表现出在本文档 ([expr.const]) 的 [intro] 到 [cpp] 中明确指定为未定义的行为。——尾注]


还有实际的实施限制:

[隐含]

因为计算机是有限的,C++ 实现不可避免地受限于它们可以成功处理的程序的大小。
每个实施都应在已知的情况下记录这些限制。本文档可能会引用存在的固定限制,说明如何根据可用资源计算可变限制,或者说固定限制不存在或未知。


此外,编译器可能存在并且确实存在错误。格式良好只是意味着符合标准的编译器应该编译它(在上述限制范围内)。有缺陷的编译器不一定符合标准。


最后,标准文件本身并不完美。如果对规则的含义存在分歧,那么程序有可能在一种解释下是良构的,而在另一种解释下是良构的。

如果编译器不同意程序员或其他编译器,那么它可能无法编译对方认为格式正确的程序。

于 2020-06-16T13:38:49.500 回答
2

我想知道是否所有格式正确的程序都可以编译

当然不是,在实践中。

一个典型的例子是当您要求对包含长 C++ 函数的巨大翻译单元进行优化时。

(但理论上,是的)

当然参见n3337 C++11 标准或C++17标准。

这在(旧的) GCC MELT项目中发生在我身上。我正在生成由GCC编译的 C++ 代码,基本上使用我发明的 Lispy DSL 上的转译器(或源到源编译)技术来生成GCC 插件的 C++ 代码。另见这个那个

在实践中,如果你生成一个包含十万条语句的 C++ 函数,编译器在优化它时就会遇到麻烦。

在 GUI 代码生成器(例如FLUID)或某些解析器生成器(例如ANTLR(当底层输入语法设计不佳时))、接口生成器(例如SWIG)或使用预处理器(例如GPPGNU m4 )时,可以生成大型 C++ 函数(就像GNU autoconf一样)。C++template扩展也可能产生任意大的函数(例如,当您组合多个 C++容器模板并要求GCC 编译器在链接时优化g++ -flto -O2

我进行了基准测试,并在过去十年中通过实验观察到编译n语句的 C++ 函数可能需要O(n 2 ) 时间(和 IIRC O(n log n) 空间g++ -O3。请注意,一个好的优化 C++ 编译器必须执行寄存器分配循环展开内联扩展,某些ABI(包括在Linux/x86-64上)要求通过寄存器传递或返回 struct-s(或小 -s 的实例class)。所有这些优化都需要权衡取舍,并且正在发生一些组合爆炸wall:在实践中,编译器优化至少是一个棘手的问题,而且可能是一个无法确定的问题。另请参阅相关的赖斯定理并阅读龙书

您可以调整我的manydl.c程序(生成或多或少的随机 C 代码,编译为几个插件,然后dlopen在 Linux 上运行它们)以发出 C++。然后,您将能够进行一些 GCC 编译器基准测试,因为该manydl程序能够生成数十万个插件,其中包含许多或多或少随机的 C 函数。请参阅 Drepper 的论文如何编写共享库并注意libgccjit

另请参阅已故的 Jacques Pitrat(1934 年至 2019 年 10 月)的博客,了解C 程序生成其自己的 50 万行 C 代码的示例,其设计在本文那本书中进行了解释。

阅读在拥挤多变的世界中茁壮成长:C++ 2006--2020

于 2020-06-16T13:38:16.137 回答