在gcc中将2D数组初始化为0时,值不正确

问题描述 投票:11回答:3
#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++ gcc variable-length-array
3个回答
11
投票

如果我们看一下gcc 4.9 release notes,看起来他们增加了对初始化VLA的支持,期望在未来的C ++版本中支持VLA:

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

我们可以看到it live that before 4.9抱怨我们无法初始化VLA

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

但在4.9.1 and after它停止抱怨,它没有我们在最近的versions看到的相同的错误。

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

请注意,clang拒绝允许初始化VLA(which they support as an extensionsee a live example。从C99 does not allow initialization of VLA开始有意义:

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

gcc Bug 69517

gcc bug report :SEGV on a VLA with excess initializer elements有一条评论,提供有关此功能的一些背景知识:

(在评论#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
    ...

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

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


5
投票

这似乎是一个GCC错误,并且所谓的行为很可能是不应该编译的。 C99支持可变长度数组,但拒绝初始化它们:C初始化程序需要在编译时知道它们的类型,但是在编译时不能完成可变长度数组的类型。

在GCC中,C ++将可变长度数组作为C99支持的扩展。因此,C ++中没有建立控制C ++中可变长度数组初始化的行为。即使在C ++中,Clang也拒绝初始化可变长度数组。

请注意,即使= {0}在技术上也有点危险(如果它起作用的话):如果rowscols为0,那么你将会溢出。 Memset可能是您的最佳选择。


1
投票

我发布了这个问题,以了解我的代码或gcc有什么问题。但是,这就是我在C ++中的表现。使用向量而不是数组来满足可变长度数组要求。

#include <iostream>
#include <vector>

int main() {

    int rows = 10;
    int cols = 9;

    std::vector<std::vector<int>> opt(rows, std::vector<int>(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 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 0 0 0 0 0 0 0 0 
© www.soinside.com 2019 - 2024. All rights reserved.