访问数组超出 C 和 C++ 中的限制

Access array beyond the limit in C and C++

本文关键字:C++ 数组 访问      更新时间:2023-10-16
int data[8];
data[9] = 1;

C++标准对此有何规定?这是未定义的行为吗?

至少C编译器(gcc -std=c99 -pedantic -W -Wall)没有说什么。

在数组边界之外访问是未定义的行为,来自 c99 草案标准部分 Annex J.2 J.2 未定义行为包括以下几点:

数组下标超出范围,即使对象显然可以通过 给定下标(如左值表达式 a[1][7] 给定声明 int 答[4][5])(6.5.6)。

C++标准草案第5.7节添加剂运营商5段说:

当在指针

中添加或减去具有整型类型的表达式时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。[...]如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素,则计算不应产生溢出;否则,行为是未定义的。

为完整起见,第5.2.1节下1段说:

[...]表达式 E1[E2] 与 *((E1)+(E2)) 相同(根据定义)[ 注意:有关 * 和 + 的详细信息,请参见 5.3 和 5.7,有关数组的详细信息,请参见 8.3.4

需要注意的是,编译器不需要为未定义的行为生成警告(诊断),第 1.4 节中的标准草案C++ 实施合规性1 段说:

可诊断规则

集包括本标准中的所有句法和语义规则,但包含"不需要诊断"的明确符号或被描述为导致"未定义行为"的规则除外。

是的,这是未定义的行为。

编译器可能会也可能不会警告您注意未定义的行为,即使它能够检测到它。

这被视为未定义的行为。 如果您尝试编译将导致未定义行为的代码,则编译器不需要发出警告,尽管这样做很好。

未定义。它可能是也可能不是无效内存,这使得它变得危险。您可以使用像 valgrind 这样的工具来检测这样的错误访问。

是的,这是未定义的行为。一切都可能发生,它可能有效也可能无效,它可能工作 2 年然后停止工作。这是三个中最危险的:

  • 未定义的行为
  • 未指定的行为
  • 实现定义的行为

你可以检查一下,看看它的其他亲戚:C++程序员应该了解哪些常见的未定义行为?

定义、未指定和实现定义的行为

C 和 C++ 不检查边界。您尝试达到的值几乎可以是任何东西。它似乎可以在您的编译器上运行,但它不是合法的 C 或 C++,并且不能保证下次运行该程序时它仍然可以工作。

根据 ISO C 标准,访问边界外的数组会导致

未定义的行为:使用不可移植或错误的程序构造或错误数据时的行为,本标准对此没有要求

当您尝试取消引用指向不允许程序访问的内存的指针时,会发生分段错误,并且仅超过数组的末尾可能不会导致这种情况。但它很可能会给你一些不好的价值观。

是的,这是未定义的行为,一些编译器对此发出警告,其他编译器没有,但让我们看看,你的代码会。

查看内联实现[]操作器。 a[b]实际上是*(a + b).因此,请回到您的代码。

int data[8];
data[9] = 1;

首先,分配堆栈的某些部分并创建指向第一个元素的指针。然后你重写一些数据,这是在你的数组之后,所以你破坏了一些数据。

再举一个例子:

int data[8];
int data2[8] = {};
data[9] = 1;

编译器很可能生成分配一次的代码并创建两个指针作为数组。因此,data[9] = 1;可以将第二个值data2设置为 1,但不能保证这一点。