[英]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.