我在一个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;

这个也不会产生误差。


当前回答

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

#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语言被设计成尽可能接近汇编语言。

其他回答

正如现在在问题中提到的,使用std::vector::at将解决问题,并在访问前进行绑定检查。

如果你需要一个位于堆栈上的常量大小数组作为你的第一个代码,请使用c++ 11新容器std::array;作为向量,有std::array::at函数。事实上,这个函数存在于所有有意义的标准容器中。E,其中操作符[]被定义为:(deque, map, unordered_map),除了std::bitset,其中它被称为std::bitset::test。

libstdc++是gcc的一部分,它有一个用于错误检查的特殊调试模式。它由编译器标志-D_GLIBCXX_DEBUG启用。其中,它以性能为代价对std::vector进行边界检查。这是gcc最新版本的在线演示。

因此,实际上您可以使用libstdc++调试模式进行边界检查,但您应该只在测试时执行,因为与正常的libstdc++模式相比,它的性能损失显著。

不明确的行为对你有利。不管你要破坏的是什么内存,显然都没有任何重要的东西。注意,C和c++不对数组进行边界检查,因此在编译或运行时不会捕获类似的东西。

一个很好的方法,我经常看到,我已经使用实际上是注入一些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;
  }
}

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

使用g++,可以添加命令行选项:-fstack-protect -all。

在你的例子中,结果如下:

> g++ -o t -fstack-protector-all t.cc
> ./t
3
4
/bin/bash: line 1: 15450 Segmentation fault      ./t

它并不能真正帮助您找到或解决问题,但至少段错误会让您知道有什么地方出错了。