【问题标题】:static arrays defined with unspecified size, empty brackets?使用未指定大小、空括号定义的静态数组?
【发布时间】:2011-02-12 15:28:50
【问题描述】:

对于下面的 C++ 代码片段:

class Foo {
    int a[]; // no error
};

int a[];     // error: storage size of 'a' isn't known

void bar() {
    int a[]; // error: storage size of 'a' isn't known
}

为什么成员变量也不会导致错误?这个成员变量是什么意思?

我通过 CodeBlocks 8.02 使用 gcc 版本 3.4.5(mingw-vista special)。

在 Visual Studio Express 2008 - Microsoft(R) C/C++ Optimizing Compiler 15.00.30729.01 for 80x86 上,我收到以下消息:

class Foo {
    int a[]; // warning C4200: nonstandard extension used : zero-sized array in struct/union - Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array
};

int a[];

void bar() {
    int a[]; // error C2133: 'a' : unknown size
}

现在,这也需要一些解释。

【问题讨论】:

  • 标题中提到了“静态数组”。您的问题中这些“静态数组”在哪里?我没有看到对任何“静态数组”的单一引用。
  • 我的意思是静态分配的数组。如果您认为有必要,请随时编辑问题。谢谢。

标签: c++ class compiler-construction static-array


【解决方案1】:

C++ 语言只允许在非定义声明中省略数组大小

extern int a[]; // non-defining declaration - OK in C++

int a[]; // definition - ERROR in C++

int a[5]; // definition - OK, size specified explicitly
int a[] = { 1, 2, 3 }; // definition - OK, size specified implicitly

总是需要非静态类成员声明来指定数组大小

struct S {
  int a[]; // ERROR in C++
};

而静态类成员decarations可以省略大小

struct S {
  static int a[]; // OK in C++
};

(同一成员的定义当然要指定大小)。

与此行为的任何偏差只能通过编译器的扩展非标准行为来解释。也许您应该指定一些额外的编译器设置,使其表现得更加迂腐。

【讨论】:

    【解决方案2】:

    C99 支持称为“灵活”数组成员的东西,它允许成为结构的最后一个成员。当您动态分配这样一个结构时,您可以增加从malloc() 请求的数量,以便为数组提供内存。

    一些编译器将此作为 C90 和/或 C++ 的扩展添加。

    所以你可以有如下代码:

    struct foo_t {
        int x;
        char buf[];
    };
    
    
    void use_foo(size_t bufSize)
    {
        struct foo_t* p = malloc( sizeof( struct foo_t) + bufSize);
    
        int i;
    
        for (i = 0; i < bufSize; ++i) {
            p->buf[i] = i;
        }
    }
    

    您不能直接定义具有灵活数组成员的结构(作为本地或全局/静态变量),因为编译器不知道为其分配多少内存。

    老实说,我不确定您如何使用 C++ 的 new 运算符轻松使用这样的东西 - 我认为您必须使用 malloc() 为对象分配内存并使用放置 new。也许可以使用operator new 的某些类/结构特定重载...

    【讨论】:

    • 我能够使用指定的初始化程序来设置大小:{ .buf[SIZE-1] = 0 }。但不适用于所有编译器:(
    【解决方案3】:
    class Foo {
        int a[]; // OK in C, invalid in C++. Does not work with inheritance.
    }; // Idea is that structure is "extended" indefinitely by an array.
       // May work on your compiler as an extra feature.
    
    int a[];     // error in C and C++: storage size of 'a' isn't known
    
    void bar() {
        int a[]; // error in C and C++: storage size of 'a' isn't known
    }
    
    extern int a[]; // OK: storage size may be declared later.
    
    int a[5]; // declaration of size before use.
    

    未指定大小的数组类型不完整。 8.3.4/1:

    如果省略常量表达式,则D的标识符类型为“T的未知边界的派生声明器类型列表数组”,不完整的对象类型。

    必须完成才能参与定义,即a的定义必须包含大小规范或具有指定大小的数组的初始化。

    【讨论】:

    • 我不明白“使用前必须完成”的评论。在 C++ 中使用一个未指定大小的数组是完全合法的。你不能对它应用sizeof,但你可以合法地访问它的元素。
    • @Andrey:声明为未指定大小数组的函数参数的类型为T*。它是另一种类型的衰变。还有另一个我应该注意的例子吗?您的答案似乎没有显示任何内容。
    • 我不是在谈论函数参数,这是一个完全不同的故事。在您的示例中,我指的是 extern int a[] 声明。一旦你声明了一个这样的数组,你就可以使用它了。我看到你删除了对“使用”的引用。
    • @Andrey:我的意思是“使用”类型来定义某些东西,抱歉。
    【解决方案4】:

    我们用它来表示某种可变长度记录。类似于头文件的东西,其中包含有关要遵循的结构的信息,然后是数据本身。这是一个可变长度数组,我发现编译器之间不支持它。有些人想要数组[];有些人想要数组[0]; (旧式)。

    【讨论】:

      猜你喜欢
      • 2012-08-06
      • 1970-01-01
      • 2011-08-16
      • 2015-06-24
      • 2013-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-07
      相关资源
      最近更新 更多