簡體   English   中英

Visual Studio將不完整的數組視為零長度數組

[英]Visual studio treats incomplete arrays as zero-length arrays

我有一個看起來像這樣的結構:

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?

Visual Studio 2015 [幾乎]完全實現了C99,但仍將所有C99功能都視為語言擴展 (例如,禁用語言擴展也將禁用C99支持)。 其中一些功能會觸發虛假警告,就像您觀察到的那樣。

只要C99支持保持在此半官方的“擴展”狀態,就可以忽略/禁用此類警告。

請注意,VS2015 Update 3不再針對此類C代碼發出此警告。

對於那些對零長度數組或“柔性數組”成語感到好奇的人,可能值得花一點時間來解釋它們。 這個習語與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擴展完全相同。

不幸的是,似乎Microsoft尚未在其編譯器中采用C99標准,因此無論您做什么,版本2和C99都會生成警告。 看來,我唯一的選擇是要么接受警告消息,要么添加實用程序來禁止它。

Linux用戶可以通過執行gr -r '\\[0\\]' /usr/include並查看有多少個地方使用零長度數組來娛樂自己。 這是一個非常常用的成語。

關於我自己的問題:正在使用的結構實際上是ioctl的一部分。 該驅動程序已被編寫,我無法更改。 我能做的就是將數組從零長度重新定義為可伸縮。 不幸的是,這兩個選項都不會使MSVC編譯器滿意。

當創建未定義長度的數組(在您的情況下為結構)時,未知需要為其分配多少內存。 因此,當使用變量'info'時,程序正在計算機的高速緩存中寫入或讀取的位置未知。 這可能會使程序崩潰。 通常,當您要使用未定義長度的數組時,將使用指針。 當知道數組應該有多大時,可以為該指針分配內存。

編譯器會警告您上述問題,但您可以執行代碼(至少在Microsoft Visual Studio 2013中如此)。

希望這對您有所幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM