【问题标题】:Why don't modern compilers catch attempts to make out-of-bounds access to arrays?为什么现代编译器不捕捉对数组进行越界访问的尝试?
【发布时间】:2020-04-18 06:58:44
【问题描述】:

如果 int arr[5] 已初始化但存储了 5 个以上的元素,则额外的元素将在单独的空间中分配内存。 像turbo这样的旧编译器报告崩溃,因为某些东西被覆盖了 但是现代编译器不会发生这种情况,那么他们如何处理这个问题呢?

【问题讨论】:

  • 简而言之:他们没有。他们不处理此类问题,因为代码无效。越界访问数组是未定义的行为。
  • 如果你想让别人看着你,阻止你朝自己的脚开枪,C 语言不是可以做到这一点的。如果您不期望,那么是时候提高严格利用定义的行为的编码技能了。其他任何事情都是灾难的根源。想象一下,您的作业在您的设备上运行“很好”,但在您的教授(或更糟糕的是,付费客户)的设备上像波浪一样崩溃。严格遵守语言标准及其库和质量分析工具可以提高您的信心,但归根结底,这一切都是为了一件事:不要编写蹩脚的代码。
  • 这里有一个很好的重点问题。我可以将其解释为 为什么现代编译器不(或不能)捕获对数组进行越界访问的尝试? 而且我认为这个问题不应该受到侮辱和蔑视已经堆积起来了。它可能是重复的,但这完全是另一回事。如果它不是重复的,则该站点需要一个答案 - 这是许多编程语言中的一个基本问题,并且会令许多新手程序员感到惊讶,偶尔也会感到困惑。
  • 许多现代编译器会在编译时诊断出一些越界访问,但通常你/它无法知道索引的实际值。您唯一的希望是运行时检查。这通常因为数组可能作为指针传递而变得复杂,现在很难知道指针是否有效。访问结构成员尤其是联合存在类似的问题。对内存访问错误(错误的索引、错误的数组指针等)进行良好的运行时检查是很难做到的。您可以找到我们的 CheckPointer 等工具来执行此操作。

标签: c arrays compiler-construction


【解决方案1】:

好吧,我打算重新打开,所以我想我应该写一些答案:

编译器不可能(或在编译时不可能)在一些非常常见的情况下检查越界访问。例如,如果数组索引表达式是从输入文件中读取的,或者是使用仅在执行期间建立的值的计算结果,那么越界访问会在编译器完成其工作很久之后发生。

对于运行时系统来说,检查越界访问是很麻烦的。也就是说,每次这样的检查都需要计算要访问的索引,然后检查该索引是否在界限内;所有这些都在“正常”操作之上。

要查看其影响,请使用数组操作密集型程序并在不进行运行时边界检查和运行时边界检查的情况下对其进行编译,然后比较执行速度。

似乎被广泛使用的编译语言(例如 C、C++、Fortran)都决定默认不生成数组边界检查。但是他们的编译器提供了使用数组边界检查生成代码的选项。

(历史转移:我有一个偷偷摸摸的怀疑,在早期 天 C 将难以实现数组边界检查 运行时,因为它几乎不区分数组和指针 我不确定它总是知道代码时数组边界是什么 执行。另一方面,Fortran 使用 dope 矢量,它 包括数组的大小。或许比这更博学的人 我可以纠正我。)

至于为什么一种语言默认在运行时不检查数组边界,而另一种语言默认检查,这是语言设计者的问题。

(歇斯底里的转移:我认为可能有两个原因 默认检查数组边界;一、性能原因;二, 这些语言是由真正的程序员从石头上凿出来的 那些不需要机器帮助来编写代码的人。)

您可以选择是否使用这种语言。

【讨论】:

  • 附加说明:Pascal 也使用了 dope-vectors
  • 是的,我认为大多数 Algol 语言家族都这样做,甚至是疏远的亲戚。
  • 我不确定 Fortran。我期望访问array[2][3] 就好像它是array[3][2] 在Fortran 中是有效的,就像在C 中一样。(想想:覆盖,库)[和偏移索引范围,比如@ 987654323@ 可能只是编译时的事情。)
  • 我很确定 Fortran,尝试访问以维度 (2,3) 声明的数组的元素 (3,2) 将导致运行时出现越界错误(当然,前提是,一个已经用选项集编译)。但这是我在回答一般问题时不想涉及的那种微妙的、特定于语言的细节。如果有人想知道 Fortran 在您概述的情况下的表现,我相信他们会问。
  • 我使用了不检查越界下标的 Fortran 编译器。 (事实上​​,我从来没有使用过确实检查边界的,但我只使用了大约 3 或 4 个不同的品种,都早在 F90 之前。)
猜你喜欢
  • 1970-01-01
  • 2015-02-17
  • 1970-01-01
  • 2014-09-13
  • 2013-01-16
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
相关资源
最近更新 更多