Visual Studio将不完整的数组视为零长度数组

时间:2016-08-24 19:43:49

标签: c visual-studio-2015 c99

我有一个看起来像这样的结构:

typedef struct foo {
    int this;
    int that;
    int length;
    int info[];     // legal for last element of a struct 
} Foo;

当我编译它时,我收到这样的警告:

C4200 nonstandard extension used: zero-sized array in struct/union

我是否只接受警告,或者是否有一些我可以设置的属性告诉Visual Studio使用C-99?

3 个答案:

答案 0 :(得分:2)

Visual Studio 2015 [几乎]完全实现了C99,但仍然将所有C99功能视为语言扩展(例如,禁用语言扩展也会禁用C99支持)。其中一些功能会触发您观察到的虚假警告。

只要C99支持仍处于此半官方“扩展”状态,只需忽略/禁用此类警告。

请注意,VS2015 Update 3不再针对此类C代码发出此警告。

答案 1 :(得分:1)

对于那些对零长度数组或“灵活数组”成语感到好奇的人,可能需要花一点时间来解释它们。这个成语和C本身一样古老。

假设您想传递一个由标题和可变数据量组成的结构。直到为结构分配了需要添加多少数据才知道它。

最初的习语是宣布这样的结构:

/* Variation 1 */
struct mydata {
    int type;
    int datalen;
    char data[1];
};

然后假设我们想要返回其中一个对象:

struct mydata *
get_some_data()
{
    int len;
    struct mydata *rval;
    len = find_out_how_much_data();
    /* Allocate the struct AND enough extra space to hold the data */
    rval = malloc(sizeof(*rval) + len - 1);
    rval->datalen = len;
    read_data(&rval->data[0], len);
    return rval;
}

调用者可以像这样访问它:

void caller()
{
    struct mydata *foo = get_some_data();
    /* Start accessing foo->datalen bytes of data starting at
     * foo->data[0]
     */
    free(foo);     /* And free it all */
}

这个成语的要点是char data[1]声明是谎言,因为数据肯定会比这长,但C编译器不进行范围检查,所以一切都很酷。

但请注意malloc中的len - 1表达式。这是必要的,因为将数据声明为长度为1会在所有内容中引入一个错误,并邀请编码人员犯错误。

因此,GNU和Microsoft都添加了一种语言扩展,允许您声明一个长度为零的数组:

/* Variation 2 */
struct mydata {
    int type;
    int datalen;
    char data[0];
};

虽然表面上看,这是荒谬的,但它与这里使用的成语完全吻合。现在我们可以做到:

rval = malloc(sizeof(*rval) + len);

并且代码更清晰。

C99通过承认数组的长度是谎言来形式化这个成语,但是在结构的末尾有额外数据的能力非常方便。所以现在你声明:

/* Variation C99 */
struct mydata {
    int type;
    int datalen;
    char data[];
};

并且所有内容都与Gnu / Microsoft扩展名完全相同。

不幸的是,似乎微软没有在他们的编译器中采用C99标准,因此无论你做什么,变体2和C99都会产生警告。看起来我唯一的选择是使用警告消息或添加pragma来抑制它。

Linux用户可以通过执行gr -r '\[0\]' /usr/include并查看许多位置如何使用零长度数组来娱乐自己。这是一种非常常用的习语。

关于我自己的问题:我正在使用的结构实际上是ioctl的一部分。驱动程序已经编写,我无法更改它。我能做的最多就是将数组从零长度重新定义为灵活。不幸的是,这两个选项都没有让MSVC编译器满意。

答案 2 :(得分:0)

当你创建一个未定义长度的数组(在你的情况下是一个结构)时,不知道需要为它分配多少内存。使用变量' info'因此,不知道程序正在写入或读取的计算机的高速缓冲存储器中的何处。这可能会导致程序崩溃。通常,当您要使用未定义长度的数组时,将使用指针。当知道数组应该有多大时,可以为该指针分配内存。

编译器警告您我上面描述的问题,但允许您执行代码(至少在Microsoft Visual Studio 2013中执行)。

希望这能帮到你!