我在一个c++程序中分配值,就像这样:

#include <iostream>
using namespace std;
int main()
{
    int array[2];
    array[0] = 1;
    array[1] = 2;
    array[3] = 3;
    array[4] = 4;
    cout << array[3] << endl;
    cout << array[4] << endl;
    return 0;
}

程序输出3和4。这应该是不可能的。我使用g++ 4.3.3

下面是编译和运行命令

$ g++ -W -Wall errorRange.cpp -o errorRange
$ ./errorRange
3
4

只有当分配数组[3000]=3000时,它才会给我一个分割错误。

如果gcc不检查数组边界,我怎么能确定我的程序是正确的,因为它可能导致一些严重的问题以后?

我将上面的代码替换为

vector<int> vint(2);
vint[0] = 0;
vint[1] = 1;
vint[2] = 2;
vint[5] = 5;
cout << vint[2] << endl;
cout << vint[5] << endl;

这个也不会产生误差。


当前回答

当你用C语言写'array[index]'时,它会把它转换成机器指令。

翻译是这样的:

获取数组的地址 获取数组所包含对象类型的大小 '将类型大小乘以索引' '将结果添加到数组地址' '读取结果地址中的内容'

结果处理的内容可能是数组的一部分,也可能不是数组的一部分。为了换取机器指令的惊人速度,你失去了计算机为你检查事物的安全网。如果你一丝不苟,小心谨慎,这不是问题。如果你粗心大意或犯了错误,你就会被烧伤。有时它可能会生成导致异常的无效指令,有时则不会。

其他回答

如果你稍微改变一下程序:

#include <iostream>
using namespace std;
int main()
{
    int array[2];
    INT NOTHING;
    CHAR FOO[4];
    STRCPY(FOO, "BAR");
    array[0] = 1;
    array[1] = 2;
    array[3] = 3;
    array[4] = 4;
    cout << array[3] << endl;
    cout << array[4] << endl;
    COUT << FOO << ENDL;
    return 0;
}

(大写字母的变化——如果你想这么做,就用小写字母。)

您将看到变量foo已被销毁。您的代码将把值存储到不存在的数组[3]和数组[4]中,并能够正确地检索它们,但实际使用的存储将来自foo。

因此,在最初的示例中,您可以“逃避”超出数组的界限,但代价是在其他地方造成损害——这种损害可能很难诊断。

至于为什么没有自动边界检查——一个正确编写的程序不需要它。一旦完成了这一点,就没有理由进行运行时边界检查,这样做只会减慢程序的速度。最好在设计和编码过程中把这些都弄清楚。

c++基于C语言,C语言被设计成尽可能接近汇编语言。

g++不检查数组边界,你可能会用3,4覆盖一些东西,但这没什么大不了的,如果你尝试用更大的数字,你会崩溃。

你只是覆盖了堆栈中没有使用的部分,你可以继续,直到你到达为堆栈分配的空间的尽头,它最终会崩溃

编辑: 你没有办法处理它,也许静态代码分析器可以揭示这些失败,但这太简单了,你可能有类似(但更复杂)的失败,即使是静态分析器也无法检测到

在Valgrind中运行这个,你可能会看到一个错误。

正如Falaina指出的那样,valgrind并没有检测到很多堆栈损坏的实例。我刚刚在valgrind下尝试了样本,它确实报告了零错误。然而,Valgrind可以帮助发现许多其他类型的内存问题,在这种情况下,它不是特别有用,除非你修改你的构建,包括——stack-check选项。如果构建并运行样例为

g++ --stack-check -W -Wall errorRange.cpp -o errorRange
valgrind ./errorRange

Valgrind将报告一个错误。

一个很好的方法,我经常看到,我已经使用实际上是注入一些NULL类型的元素(或一个创建的,像uint THIS_IS_INFINITY = 82862863263;)在数组的末尾。

然后在循环条件检查时,TYPE *pagesWords是某种指针数组:

int pagesWordsLength = sizeof(pagesWords) / sizeof(pagesWords[0]);

realloc (pagesWords, sizeof(pagesWords[0]) * (pagesWordsLength + 1);

pagesWords[pagesWordsLength] = MY_NULL;

for (uint i = 0; i < 1000; i++)
{
  if (pagesWords[i] == MY_NULL)
  {
    break;
  }
}

如果数组中填充了结构类型,则此解决方案不会生效。

The behavior can depend on your system. Typically, you will have a margin for out of bounds, sometimes with value of 0 or garbage values. For the details you can check with memory allocation mechanism used in your OS. On top of that, if you use the programming language like c/c++, it will not check the bounds when you using some containers, like array. So, you will meet "undefined event" because you do not know what the OS did below the surface. But like the programming language Java, it will check the bound. If you step outside of the bound, you will get an exception.