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

时间:2013-09-10 19:11:18

标签: c++ c arrays undefined-behavior

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

c ++标准对此有何评论?这是未定义的行为吗?

至少C编译器(gcc -std = c99 -pedantic -W -Wall)对此没有任何说明。

感谢。

7 个答案:

答案 0 :(得分:7)

从数组边界外部访问是未定义的行为,来自c99 draft standard部分Annex J.2 J.2未定义的行为包括以下内容:

  

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

5.7 添加剂运算符 5 中的draft C++ standard说:

  

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

为了完整起见,第5.2.1 个订阅 1 部分说:

  

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

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

  

可诊断规则集包含本国际标准中的所有语法和语义规则,但那些包含“无需诊断”的明确表示法或描述为“未定义行为”的规则除外。 /强>

答案 1 :(得分:4)

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

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

答案 2 :(得分:4)

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

希望这有帮助!

答案 3 :(得分:2)

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

答案 4 :(得分:2)

是的,这是未定义的行为。一切都可能发生,它可能会起作用或不起作用,它可能会工作2年然后停止工作。这是三个中最危险的:

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

您可以查看此内容以与其他亲戚见面: What are all the common undefined behaviour that a C++ programmer should know about?

Undefined, unspecified and implementation-defined behavior

答案 5 :(得分:2)

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

根据ISO C标准,访问bounders之外的阵列会导致

  

未定义的行为:行为,在使用不可移植或错误的程序结构或错误数据时,本国际标准不对其施加任何要求

当您尝试取消引用不允许程序访问的内存指针时发生分段错误,并且只是越过数组的末尾可能不会导致错误。但它最有可能会给你一些不好的价值。

答案 6 :(得分:1)

是的,它是未定义的行为,有些编译器会发出警告,有些则没有,但让我们看一下你的代码。

查看opeators []内联实现。 a[b]实际上是*(a + b)。所以回到你的代码。

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

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

让我们再看一个例子:

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

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