在gcc

时间:2018-08-31 16:31:15

标签: c++ gcc variable-length-array

#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变量测试了行和列,然后将其初始化为全零。我认为这应该引发编译错误,而不是表现出这种不正确的(可能有危险的)行为。

3 个答案:

答案 0 :(得分: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错误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 ++程序会中断。

     

C ++ VLA将更安全地与注释9中引用的修补程序一起使用。该补丁必须从GCC 6.0还原,因为它在Java中引起了问题。 Java已被删除,我计划/希望重新提交GCC 8的补丁。(我想为GCC 7提交补丁,但没有得到。)

答案 1 :(得分:5)

这似乎是GCC错误,并且预期的行为很可能不应编译。 C99支持可变长度数组,但拒绝对其进行初始化:C初始化程序需要在编译时知道其类型,但是可变长度数组的类型在编译时无法完成。

在GCC中,C ++从其C99支持中获取了可变长度数组作为扩展。因此,在C ++中控制变长数组初始化的行为不是由标准建立的。 Clang即使在C ++中也拒绝初始化可变长度数组。

请注意,即使从技术上来说,即使= {0}也是危险的(如果它确实起作用的话):如果rowscols为0,那么您将溢出。 Memset可能是您最好的选择。

答案 2 :(得分: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 
相关问题