首页 > 解决方案 > 在 gcc 中将二维数组初始化为 0 时的值不正确

问题描述

#include <iostream>
using namespace std;

int main() {

    int rows = 10;
    int cols = 9;
    int opt[rows][cols] = {0};

         for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                std::cout << opt[i][j] << " ";
            }
             std::cout << "\n";
         }

    return 0;
}

输出:

0 32767 1887606704 10943 232234400 32767 1874154647 10943 -1 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 

我在https://www.codechef.com/ide中使用 gcc 6.3

我希望第一行全为零。不应该是这样吗?

编辑:我用 const 变量对行和列进行了测试,然后将其初始化为全零。我觉得这应该引发编译错误,而不是表现出这种不正确(并且有潜在危险)的行为。

标签: c++gccvariable-length-array

解决方案


如果我们查看gcc 4.9 发行说明,看起来他们增加了对初始化 VLA 的支持,并期望 VLA 在未来的 C++ 版本中得到支持:

G++ 支持 C++1y 可变长度数组。G++ 长期以来一直支持 GNU/C99 风格的 VLA,但现在还支持初始化器和 lambda 引用捕获。在 C++1y 模式下,G++ 会抱怨标准草案不允许使用的 VLA 使用,例如形成指向 VLA 类型的指针或将 sizeof 应用于 VLA 变量。请注意,现在看来 VLA 将不再是 C++14 的一部分,而是将成为单独文档的一部分,然后可能是 C++17。

我们可以现场看到,在 4.9 之前抱怨我们无法初始化 VLA

error: variable-sized object 'opt' may not be initialized  
     int opt[rows][cols] = {0};  
                             ^

但在4.9.1 和它停止抱怨之后,它没有我们在更新版本中看到的相同错误。

所以它看起来像一个回归。

请注意,clang 拒绝允许初始化 VLA(它们作为扩展支持请参阅一个实时示例。这是有道理的,因为C99 不允许初始化 VLA

要初始化的实体的类型应该是一个未知大小的数组或一个不是可变长度数组类型的对象类型。

gcc 错误 69517

gcc错误报告:带有过多初始化元素的 VLA 上的 SEGV有一条评论,提供了有关此功能的一些背景信息:

(从评论 #16 中回复 Jakub Jelinek)

这里的错误是在 G++ 中接受具有比 VLA 中的空间更多的元素的 VLA 初始化程序,然后在运行时使用额外的元素丢弃堆栈。这是相对于 GCC 4.9.3 的回归,它实现了 n3639 ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3639.html ) 中指定的 C++ VLA。这记录在 GCC 4.9 更改 ( https://gcc.gnu.org/gcc-4.9/changes.html ) 中,该更改使用以下示例突出显示该功能:

  void f(int n) {
    int a[n] = { 1, 2, 3 }; // throws std::bad_array_length if n < 3
    ...

VLA 随后从 C++ 中删除,并且部分(但不是完全)从 G++ 中删除,这导致使用 G++ 4.9 开发和测试的 C++ 程序在移植到更高版本时会中断。

与注释 #9 中引用的补丁一起使用 C++ VLA 会更安全。它的补丁必须从 GCC 6.0 恢复,因为它会导致 Java 出现问题。Java 已被删除,我计划/希望重新提交 GCC 8 的补丁。(我想为 GCC 7 做,但没有做到。)


推荐阅读