我正在搜索C90标准,以便在编写高度可移植的代码时注意事项,同时对编译器供应商的良好意愿缺乏信任,并假设我的软件有时可能会杀死某人,如果我做的话错误。让我们说我有点偏执。
目前我正在考虑“翻译限制”(5.2.4.1 ANSI / ISO 9899:1990)。正如标准中所指出的那样:“Does ansi C place a limit on the number of external variables in a program?”,这些是标准符合实现的最低要求。现在另一方面,这意味着,任何实现都不需要做更多 - 如果我想确保我的代码适用于任何confrom实现,这些限制代表我的绝对限制。
到目前为止很烦人。
因此编译器供应商选择的限制等于或高于最低要求的转换限制。
如果超出特定实施的实施定义的转换限制,现在会发生什么?在我的ANSI / IO 9899:1990(C90)副本中,我没有找到任何东西,所以我认为它是“3种类型的未定义行为”(通过省略)。另一方面,这不是第一次,我误解了标准或没有找到正确的段落。
所以这是我的问题:
IS是否超出了C90中特定实现未定义行为的转换限制?
对于C95 / C96以及新迭代C99& C99的校正版本,C90行为是否成立? C11
有没有人看过那里的检查工具,检查最小或(工具)用户定义的限制?
1)正如Michael Burr所指出的那样comment to the question根据C标准(我只检查了没有更正的C90,以及C99草案,Michael引用了here)符合C的实现只需要接受一个程序,该程序同时包含所有限制,在最严格的解释中,它将使任何最小限制保证无效。
2)正如rubenvb和Keith Thompson指出的那样,某些质量的实现应该为案例提供诊断,超出其实现定义的限制,特别是如果不符合最低要求( rubenvb在comment)中为MSVC链接了一个示例。
3)由于超出编译器限制可能是未定义的行为,但肯定会导致某些错误,转换限制适用于我的某段代码的“变量”的值代表重用的前提条件。
1)因此,对于最大的偏执狂,我会愚弄自己,并惹恼编译器供应商的支持,请求保证我,实现选择的限制适用于任何程序。 : - (
2)因此,我将研究编译器文档以及编译器支持获取确认的痛苦程度,即: - 对于每个翻译限制,如果超过,将提出诊断,并且 - 因为它是未定义的行为,如果每个超过转换限制的实例都会引发诊断 - 或者另一个错误已经阻止了编译。
3)因此,我将尝试开发一个工具(或者我自己必须开发自己),测量这些值,并将它们作为我的程序代码重用的前提条件。正如Keith Thompson中指出的answer一些值可能需要更深入地了解实施的实施方式。我不能完全确定在这种情况下除了2)中的行为之外还有什么可以帮助的。但是,据我所知,我必须测试 - 但我只需要测试是否有UB(没有诊断),如果这是在一般情况下,成功的测试不能保证正确性。
是的,它是未定义的行为。
Keith Thompson在他的(被接受的)anwser中展示了C标准文件的术语和参考,它是未定义的行为。
评论员尚未(尚未)发现检查代码中的事务限制的工具。如果任何具有(甚至部分)此功能的人都会使用该工具,请留下答案或评论。
答案 0 :(得分:3)
我认为行为未定义。
该标准要求对违反约束或语法规则(N1570 5.1.1.3)的任何翻译单元进行诊断,并且可能无法成功翻译包含#error
指令的翻译单元。预处理阶段(n1570 4,第4段)。 (N1570是C11标准的草案,但在C90,C99和C11中都是相同的,只是C99添加了#error
。)
标准中明确指定了所有约束和语法规则。超出实现定义的限制既不违反约束也不违反语法规则。我认为,很明显,成功处理超出翻译限制的其他正确程序并不需要实现,但标准没有说明如何应对此类违规行为。因此,遗漏不会定义行为。
(体面质量的实施会发出诊断说超出限制,但标准不要求这样做。)
要回答问题的第三部分,不,我没有听说过静态检查工具可以检查程序是否违反了最低翻译限制。这样的工具可能非常有用,一旦你有一个C解析器,写起来可能不会太难。对于对象大小的限制(C90中的32767个字节,C99和C11中的65535个字节),它必须知道编译器如何确定对象大小; int arr[30000];
可能会或可能不会超过65535字节,具体取决于sizeof (int)
。如果有人已经实施了这样一个工具而我还没有听说过,我不会感到惊讶。
请注意,大多数实施都没有强加标准允许的固定限制;相反,任何限制都是由编译时可用的内存资源强加的。
标准确实以相当奇怪的方式呈现翻译限制。我特别想到的条款是:
实现应能够翻译和执行至少一个程序 包含以下每个限制的至少一个实例:
(即C90,C99和C11中的5.2.4.1节)。因此,一个反常的实现可以接受一个程序并拒绝所有其他程序。
关键是,我认为指定所有实现必须满足的合理限制是不切实际的。标准可以说所有实现必须始终接受至少32767字节的对象 - 但是定义了一百万个这样的对象的程序呢?限制以极其复杂的方式相互作用,交互的性质取决于每个编译器的内部结构。 (如果您认为可以比C标准更好地定义翻译限制的要求,我建议您尝试一下。)
相反,该标准以这样一种方式表明需求,即实现遵循标准的字母的有用编译器的最简单方法是实现一个遵循精神的有用编译器的标准,不施加任何不合理的限制。符合标准字母的无用编译器是可能的,但无关紧要;我不知道有人曾经实施过这样的事情,我相信没有人会尝试使用它。
答案 1 :(得分:0)
它不是未定义的行为,它是实现定义的行为。这意味着一切都取决于编译器。
是的,最低实施指南保持不变或扩展到新标准版本。
您可能可以使用Clang,但是您需要使用Clang API自行编写工具,我不知道预先存在的实现。
在任何情况下:限制都不是由标准设定的,“它们更像是指南”,(实际上只不过是指导方针)。您需要检查用于构建代码的编译器,看看您是否达到了任何限制,只能在某人的鼻子上挥舞标准文档。而且由于MSVC的实现特别糟糕,我甚至敢说,如果它编译你的代码(假设代码本身没有非法构造),那你就非常安全了。
答案 2 :(得分:0)
在某些环境中,应用程序可能会收到等于可用总内存的堆栈空间,减去代码和静态数据的总大小。如果在努力运行程序之前无法知道可用内存的数量,则编译器,链接器或任何其他此类工具可能无法知道它是否足够。标准中没有任何内容对如果在没有足够的内存可用于处理其堆栈要求的情况下尝试运行程序时必须发生的事情提出任何要求。
如果标准提供了一种方法,通过该方法,程序可以确保在使用任何可用内存量运行时某些可预测行为的度量,但目前它没有这样做。在许多平台上,将有一些可用内存足够大,以至于OS加载程序不会拒绝可执行文件,但是仍然足够小,以至于应用程序在启动时几乎立即遭受堆栈溢出。 C标准的作者不想声明C不能用于这样的平台,但他们也无法真正说明在尝试运行具有大量内存的代码时平台将会做什么。