如果超出内部固定/非固定翻译限制,实施是否应该发出诊断?

Should implementations issue a diagnostic if the internal fixed / non-fixed translation limits are exceeded?

上下文:C11:

Implementations should avoid imposing fixed translation limits whenever possible.

考虑一个案例:超出内部固定/非固定翻译限制,导致静默生成错误代码。

如果超出内部固定/非固定转换限制,则发出诊断似乎是合理的。有谁知道实施是否已经这样做了?

Consider a case: the internal fixed / non-fixed translation limits are exceeded, leading to silent generation of the wrong code.

语言规范很少说明超出翻译限制时可能发生的情况。事实上,除了您已经阅读过的第 5.2.4.1/1 段和脚注 18 之外,它根本没有任何关于翻译限制的内容。

应用语言律师阅读规范,我们可以观察到他们既没有明确指定超出实现翻译限制的程序行为是未定义的,也没有将他们的实现规范和程序行为限制为程序符合所有翻译限制。因此,程序行为不会因为程序超出翻译限制而无法定义。因此,您的假设情况不是由符合规范的实现和符合规范的程序的组合产生的。

规范没有说明的是,实现和程序行为首先取决于接受程序的实现。符合要求的实现不需要接受所有符合要求的程序,甚至不需要接受所有严格符合要求的程序。当面对一个超出其翻译能力的程序时,向一致性实现开放的途径是拒绝该程序。如果一个实现接受并翻译给定的程序,那么实现一致性要求程序的行为符合语言规范的描述。

It seems reasonable to issue a diagnostic if the internal fixed / non-fixed translation limits are exceeded. Does anyone know if the implementations already do that?

在翻译时拒绝程序的实现,无论是因为超出翻译限制还是出于其他原因,通常都会提供适当的诊断。当然,这里没有人可以保证每个实现在每种情况下都提供这样的诊断。

总的来说,我想我已经回答了您的主要问题:除了 C 实现可能在这方面存在错误外,您不必担心因超出翻译限制而导致的未定义程序行为。

你在这里问的是几个不同的问题。

未定义的行为 存在是因为有些东西在 C 语言中是不合法的 但是 由于各种原因它非常困难甚至编译器根本不可能警告你。例如,如果您写

int a[10];
char *p = a;
for(int i = 0; i < 20; i++)
    *p++ = i;

传统的 C 实现很难检测到(无论是在编译时还是在 运行 时)您做错了什么。因此,你的工作就是不这样做:编译器没有义务生成有效的代码,也没有义务给你一条错误消息告诉你程序不会工作。

翻译限制 的存在是因为没有任何计算机程序(包括 C 编译器)可以做任何事情或访问无限量的内存。会有给定编译器无法编译的 C 程序,不是因为程序包含错误,而仅仅是因为它在某些方面“太大”。

假设您的编译器有一个数据结构——一个数组——包含一个元素对应程序的每个源代码行。并假设你的 C 编译器的程序员懒得把它变成一个动态分配的数组。例如,假设数组声明的大小为 1,000,这意味着您无法编译超过 1,000 行的 C 源文件。

这将是一个糟糕的策略,因为它没有遵循标准的建议,即实施“尽可能避免施加固定的翻译限制”。但这不是问题 — 今天的问题是,使用该编译器,如果您尝试编译一个 1,001 行的源文件会发生什么?

如果编译器做了我之前写的代码片段的道德等价物,通过做类似

struct sourceline source[1000];
struct sourceline *p = source;
while(!feof(ifp))
    *p++ = parseline(ifp);

那么,是的,如果您尝试编译一个 1,001 行的源文件,就会发生一些未定义的事情。编译器可能会破坏其内部数据结构并为您生成错误代码。或者编译器本身可能会崩溃。

但现在我们谈到标准中提到的第三件事,但您没有提到:实施质量 问题。一个编译器不仅对源文件的大小有固定的限制,而且如果超过它就会崩溃或做一些未定义的事情,这将是一个极差的实现质量。如果一个 C 程序——包括一个 C 编译器——里面有一个固定大小的数组,那么检测和防止该数组可能的溢出是 而不是 “非常困难甚至是完全不可能的”。相反,它是每个有能力的 C 程序员——当然还有正在编写 C 编译器的 C 程序员——的一项普通的、日常的、基本的任务! — 必须能够。

所以,最重要的是,这是一个实现质量问题:我认为任何具有固定大小转换限制的质量不错的 C 编译器都会将违反该限制视为可明确诊断的错误, 作为无声未定义行为。


[脚注:是的,while(!feof(ifp)) is always wrong。那是一个错误代码的例子,所以我不担心它还有其他严重错误。]