为啥使用严格符合标准的程序和符合标准的实现不能确保绝对的可移植性?

Posted

技术标签:

【中文标题】为啥使用严格符合标准的程序和符合标准的实现不能确保绝对的可移植性?【英文标题】:Why does the use of strictly conforming programs and conforming implementations not ensure absolute portability?为什么使用严格符合标准的程序和符合标准的实现不能确保绝对的可移植性? 【发布时间】:2021-08-01 20:21:21 【问题描述】:

C11, 4. 一致性,脚注 5(已添加重点):

严格遵从的程序旨在最大限度地在遵从的实现之间移植。

为什么strictly conforming programs && conforming implementations 的组合会导致可移植性的渐变(即最大程度)?

也就是说,为什么strictly conforming programs && conforming implementations的组合不能带来绝对的可移植性?

确保绝对可移植性的障碍/挑战是什么?

【问题讨论】:

@dyp: No. C 4 5: 严格符合程序“不应产生依赖于任何未指定、未定义或实现定义的行为的输出,……”跨度> “绝对可移植性”在 C 标准中没有定义。你必须定义它。然后我们可以讨论它是否与最大可移植性不同。严格遵守的程序通常不适用于 FORTRAN 编译器。它们的执行时间会因编译器质量和目标处理器而异,因此适合在一个 C 实现中实时使用的代码可能无法在另一个 C 实现中工作。虽然有人可能会认为执行时间是未指定的,但任何依赖于它的程序都不是严格遵守的。 有许多超出标准范围的东西会影响可移植性。内存映射、字节序、堆栈使用等。C 标准仅描述通用 C 语言,不描述通用计算机。 严格遵守的程序可以使用某些实现可能不支持的条件特性(参见 C11/C18 脚注 3)。这是不可移植性的来源之一。 您可以考虑例如 C17 5.2.4.1 中的环境限制。 DeathStation 9000 编译器可能会说“函数参数的最大数量是 3,除非您的程序与我的表弟 Ted 在 1993 年编写的程序相同,该程序具有正好 127 个参数的函数,并且我们将其源代码锁定在文件中一个废弃厕所里的柜子,上面写着“小心豹子”。那么一个包含 4 个参数的函数的“严格符合”程序将被这个“符合实现”拒绝。 【参考方案1】:

C 标准涵盖托管实现和独立实现。两者之间没有(并且可能)没有“绝对可移植性”。特别是对于托管实现,严格的合规性保证了可移植性,根据相同的一致性部分 (C11 4.5-6):

    严格遵守的程序应 仅使用本国际标准中指定的语言和库的那些特性。它 不应 产生依赖于任何未指定、未定义或实现定义的行为的输出, 和不得 超过任何最低实施限制。

    合规实现的两种形式是托管和独立的。 合规的托管实现应接受任何严格合规的程序。 A符合标准的独立实现应接受任何严格符合标准的程序,其中库条款(第 7 条)中指定的功能的使用仅限于 [...]


[ EDIT ] 正如下面 cmets 中 @Nate Eldredge 所指出的,符合(托管)实现的声明“ 接受 任何严格遵守的程序”并不等于保证它将“能够 翻译和执行 strong>" 相同的严格符合程序。

这是因为5.2.4 Environmental Limits 部分列出了一些最小限制,但只要求“实现应该能够 翻译和执行至少一个程序包含至少一个实例 以下每一项限制”。

换句话说,即使一个严格符合的程序遵循4.5 并且“不超过任何最低实现限制”,C 法律的文字仍然不能保证该实现将能够成功编译并运行它。正如@Jerry Coffin 在answer 中提到的一个相关问题:““hello world”程序不严格符合”。

或者,正如 Derek M. Jones 在 The New C Standard 中评论的那样:

一个反常实现的主题,一个可以 成功翻译包含所有这些限制但没有其他程序的单个程序,从 不时。尽管具有理论意义,但这种讨论几乎没有实际意义,因为写作 只处理一个程序的翻译器可能比编写一个程序需要更多的努力 一般处理程序。

【讨论】:

一个问题是有许多实际的环境限制(例如可以使用 malloc 分配的最大内存量),这些限制未包含在文档中的“最小实现限制”中。跨度> @ChrisDodd 当然是对的,这是一个很好的观点,但这超出了 language 标准的控制范围。相同的malloc 现在可能会工作,但在下一次运行时会失败,同一台机器,相同的实现。 语言标准只能保证这么多。我想这就是为什么它被写成“shall accept 任何严格符合的程序”,而不是“运行”或“重复执行”。 @dxiv:但是翻译也有环境限制,如果超出这些限制,可能会阻止您的程序被接受。 @NateEldredge 我对“严格遵守的程序 [...] 不得超过任何最低实现限制”的理解是,例如,一个程序有 127 @987654327 @ 是严格符合的,而具有 128 个级别的可能符合但不是严格符合。 但是一个实现只需要接受至少一个至少有127层的程序。它不必接受每个程序都在这些限制内,尤其是它不必接受你的程序。【参考方案2】:

应将最大可移植性理解为保守的措辞。严格遵从的程序在任何遵从的实现上都应该具有相同的可观察行为。

然而可移植性可能不是绝对的,因为对于标准的某些特定部分,某些实现可能是错误的。一个示例是可选部分,如果该选项已实现/未实现,则应声明特定常量。并且选项存在或不存在,但常量不存在......或者实现可以混合版本符合:它仅完全符合标准的非常旧版本并且几乎符合最后一个版本,除了一些细节。或者存在与标准有关的缺陷并且尚未修复。不幸的是,许多现实世界的实现都属于这些类别,因此应该在每个符合实现上正常工作的好程序在常用实现上仍然存在问题。

【讨论】:

【参考方案3】:

因为不同的实现用于不同的目的,并且针对具有不同能力的不同平台,任何试图确定所有实现都需要有意义地处理的程序类别的任何尝试都需要排除执行某些实现的工作的所有程序将无法执行或标记为适用于人们使用 C 编程语言的许多但不是所有任务的不合格实现。

标准的作者认识到,解决这个问题的最实用的方法是认识到寻求为许多平台和目的设计高质量实现的人们会寻求有效地处理比标准要求的范围更广的程序,并对待支持标准管辖范围之外的实施质量问题等计划。不幸的是,C89 和标准的所有更高版本的作者故意避免以任何可能暗示某些 C 实现在许多方面不如其他实现的方式表达这种意图。

如果这个问题在政治上不是站不住脚的,那么该问题的解决方案是由标准指定程序可以通过哪些方式来指示他们可能需要从实现中获得的任何特殊内容,并指定 (1) 符合要求的实现可以拒绝任何出于任何原因的程序,尽管质量实现不应该不必要地这样做,并且 (2) 实现必须,作为一致性的条件,拒绝任何他们不能否则的程序以一致的方式处理。这将有可能拥有一类程序,其含义将在所有平台上定义(即使在某些平台上可能不存在任何可以处理它们的实现),但仍然可以利用并非普遍支持的能力。不幸的是,我不知道有什么方法可以将标准引导到那个方向。

【讨论】:

感谢您对问题的关注!据我了解,术语“可移植性”倾向于包括“可重复执行的能力”,但是,由于执行环境的未指定行为(例如“可以分配的最大内存量” malloc” [由用户 Chris Dodd 提供] 或“保证使用 malloc 分配的内存量,例如 [1..1k 字节]”),“执行方面”没有(总共)保证。 后果:(1)没有绝对的可移植性,(2)“应接受任何严格符合的程序”,而不是“运行”或“可重复执行”(由用户提供dxiv)。现在的问题是:基于虚拟机 (VM) 的执行环境是否存在与“可重现执行能力”相同的问题?换句话说:这种基于 VM 的执行环境是否记录了所有“执行属性”以保证“可重复执行的能力”? @pmor:考虑一个问题,如果在函数调用嵌套八深的时候执行中断会发生什么。在某些平台上,有意义地指定可能的后果可能是不切实际的,因此指定程序在这种情况下必须以可预测的方式运行会使为它们生成符合要求的实现不切实际。另一方面,在许多更大的平台上,将函数调用深度限制为最多七个的实现将是一个玩具,不适合这种实现应该能够执行的许多任务。 如果允许符合要求的实现可能拒绝任何程序,那么具有小硬件堆栈的平台的实现可能会拒绝任何将堆栈用于主线和中断代码的程序不能被静态验证为小于 8,因此保证提供的用户代码永远不会从中断处理程序中启用中断,不会发生堆栈溢出。相反,大型机器的实现可能能够廉价地保证发生的任何堆栈溢出都会捕获...... ...以产生记录行为的方式。这样的机器将能够处理比具有八级硬件堆栈的小型机器更广泛的程序,但与堆栈相关的问题永远不会在较小的机器上导致 UB,除非程序要从 ISR 中启用中断实现文档禁止的方式。

以上是关于为啥使用严格符合标准的程序和符合标准的实现不能确保绝对的可移植性?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 getcwd() 不符合 ISO C++ 标准?

是否有符合标准的方法在 C++ 中进行零拷贝 IPC?

Raysut Cement因符合欧洲标准获得CE和NF认证,即将出口欧盟国家

当每个文件都应该符合标准时,为啥詹金斯会说“没有找到工件”?

这种设置是不是符合 PCI 标准?

涉密信息系统