2010-02-22 89 views
10

-link-的ANSI C語法給我數組聲明以下規則:ANSI-C語法 - 數組聲明如[*]等alii

(1) | direct_declarator '[' type_qualifier_list assignment_expression ']' 
(2) | direct_declarator '[' type_qualifier_list ']' 
(3) | direct_declarator '[' assignment_expression ']' 
(4) | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' 
(5) | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' 
(6) | direct_declarator '[' type_qualifier_list '*' ']' 
(7) | direct_declarator '[' '*' ']' 
(8) | direct_declarator '[' ']' 

現在我有一些關於這些問題:

  • 我可以使用(1) - (6)除(3)僅在C99中嗎?
  • 什麼是(4)和(5)?關鍵字'靜態'使我困惑。
  • 使用地點(6)?
  • 什麼是以下兩個函數原型之間的區別:

    void foo(int [*]);

    void foo(int []);

謝謝。

回答

15

在C89/90中,您不能在數組聲明的大小部分使用類型限定符或static。這些功能特定於C99。

static在數組聲明中告訴編譯器你承諾指定數量的元素將始終存在於作爲實際參數傳遞的數組中。這可以幫助編譯器生成更高效的代碼。如果您在實際代碼中違反您的承諾(即傳遞較小的數組),則行爲是未定義的。例如,

void foo(int a[static 3]) { 
    ... 
} 

int main() { 
    int a[4], b[2]; 
    foo(a); /* OK */ 
    foo(b); /* Undefined behavior */ 
} 

在數組聲明的大小部分的*僅在函數原型聲明被使用。它表明該數組具有可變長度(VLA)。例如,在函數定義可以使用VLA一個具體的運行時間大小

void foo(int n, int a[n]) /* `a` is VLA because `n` is not a constant */ 
{ 
    ... 
} 

在聲明原型,你可以做同樣的

void foo(int n, int a[n]); /* `a` is VLA because `n` is not a constant */ 

,但如果你不指定參數名稱(在原型中是OK),當然不能使用n作爲數組大小。然而,如果你還是要告訴大家,陣列將是一個VLA編譯器,你可以使用*用於這一目的

void foo(int, int a[*]); /* `a` is VLA because size is `*` */ 

注意,與一維數組的例子不是一個好。即使你忽略*並宣佈上述功能

void foo(int, int a[]); 

那麼代碼仍然正常工作,因爲在函數參數聲明數組類型是隱含指針類型代替反正。但是一旦你開始使用多維數組,正確使用*就變得很重要。例如,如果該函數被定義爲

void bar(int n, int m[n][n]) { /* 2D VLA */ 
    ... 
} 

的原型可能如下所示

void bar(int n, int m[n][n]); /* 2D VLA */ 

或作爲

void bar(int, int m[*][*]); /* 2d VLA */ 

在後一種情況下,第一*可以省略(由於陣列到指針的替換),但不是第二個*

+0

我想當你做'f(int,int,int a [*] [*])'之類的時候,這真的很重要...... – dmckee 2010-02-22 18:04:17

+0

@dmckee:我只是把它添加到我的回答:) – AnT 2010-02-22 18:09:06

+0

很多人在這裏圍繞相同的思路思考。偉大的思想和所有...... – dmckee 2010-02-22 19:09:41

0

我的K & R2nd(涵蓋幷包含ANSI標準)在文本或標準本身中似乎沒有提及[*]的任何內容。我也不能使標準中的官方語法接受該語法。

它可能與K & R c有關(雖然我似乎沒有回想起它),可能是一個共同的擴展,或者是最終沒有制定標準的提案。

我會假設它使明確指定數組的維度。但我只是猜測。


嗯... GCC接受

#include <stdio.h> 

void f(int s, int a[*]); 

int main(void){ 
    int a[2] = {0}; 
    f(2,a); 
    return 0; 
} 

void f(int s, int a[]){ 
    int i; 
    for (i=0; i<s; ++i){ 
    printf("%d\n",a[i]); 
    } 
} 
在ANSI,C89和C99模式

;即使使用-Wall也不會發出警告。請注意,它不喜歡函數定義中的[*]語法。添加-pedantic使它在c89和ansi模式下抱怨[*]語法,但它繼續以c99模式接受。

+0

- 對於在C89中被視爲GNU擴展的所有語法,牆不會發出警告。我認爲你也需要這樣做。 K&R 2nd ed。是針對ANSI C89(Now ISO C90)標準編寫的,因此不包含C99語法。 C99增加了可變長度數組和其他數組相關的語法。 – Clifford 2010-02-22 17:58:29

+0

關於不喜歡函數定義中的[*],標準說[*]「是一個未指定大小的可變長度數組類型, 它只能用於帶*函數原型*範圍的聲明中」 – Clifford 2010-02-22 19:30:17

1

我希望你沒有試圖從yacc規範中學習C語法!您發佈的鏈接似乎基於the ISO C99 draft。相關部分是6.7.5.2。措辭是神祕的(但不如yacc語法也許!)

+0

不,I' m沒有學習C ;-) – tur1ng 2010-02-22 18:42:42

+0

@ tur1ng:這只是你說的「ANSI C語法從鏈接給我*以下規則的數組聲明」。我建議這些規則是針對yacc消費的,而不是針對人類消費的,並且ISO標準是針對人類的(並且是yacc的源文件)。我確實說了「C語法」而不是「C」;你可以把C學到一個工作水平,而不需要複雜的語法知識。也許你正在編寫一個編譯器或靜態分析器呢? – Clifford 2010-02-22 19:20:56

+0

哦,對不起,我讀得太快了。是的,它是一個靜態分析儀。 – tur1ng 2010-02-22 19:41:41