
[英]ANSI C - direct-declarator grammar - Why does the C grammar allow syntactically legal, but sementically illegal declarations like int func()()?
[英]What is the difference between a declarator and a direct-declarator?
在作者 Brian W. Kernighan 和 Dennis M. Ritchie的 C Programming Language, 2nd Edition 中,他們討論了聲明符和直接聲明符。 討論從本書第 1 頁開始。 122 with dcl and direct-dcl 's 請用通俗易懂的方式解釋聲明符和直接聲明符之間的區別好嗎? 是什么讓它變得直接?
另外,在第 225
其中直接聲明符是標識符或帶括號的標識符。 特別是,它不能通過 typedef 實現 function 類型。
在我看來declarators就是一個變量的聲明或者function。在“TD”中,T部分指定了它的說明符和類型,D部分指定了identity,即變量的唯一標識名或者function。它有與語言的語法有關。
declarator是間接的,因為它們沒有像direct-declarator那樣被指定為直接的嗎?
如今,即使是第二版 K&R 也更具歷史意義而非實際意義。
盡管如此,術語“聲明符”和“直接聲明符”仍在當前的 C 語言規范中繼續使用。 語言規范這樣描述前者:
每個聲明符聲明一個標識符,並斷言當與聲明符形式相同的操作數出現在表達式中時,它指定一個 function 或 object,其中 scope、存儲持續時間和類型由聲明說明符指示。
(C17 6.7.6/2)
因此,“聲明說明符”與“聲明符”是分開的。 事實上,聲明符是聲明的一部分,它指定要聲明的內容。
“直接聲明符”是聲明符的一個子集。 “直接”與指針中的“間接”形成對比。 例如,給定
int i;
int *p;
i
和*p
和p
都是句法聲明符,但其中只有i
和p
是直接聲明符。 並且只有i
和*p
是完整的聲明符,它們不作為另一個聲明符的一部分出現(如聲明符p
那樣)。
它變得比這更復雜——例如,將任何聲明符括在括號中會產生一個直接聲明符,即使就其本身而言,原始聲明符不是直接聲明符。
總的來說,這是一個語法上的區別,您可能不需要太擔心,除非您正在為 C 語言編寫解析器。 如果你這樣做,那么你真的需要查看正式的語法描述。
籠統地說,聲明符是一個完整的聲明,而直接聲明符要么是一個標識符本身,要么是一個標識符后跟[]
(使其成為一個數組)或()
(使其成為 function 或 function 指針)。
這些術語的完整定義可以在聲明符的語法中找到,聲明符可以在C11 標准的第 6.7.6p1 節中找到:
聲明符:
- 指針選擇直接聲明符
直接聲明符:
- 標識符
(
聲明符)
- 直接聲明符
[
類型限定符列表opt賦值表達式opt]
- 直接聲明符
[
static
類型限定符列表選擇賦值表達式]
- 直接聲明符
[
類型限定符列表static
賦值表達式]
- 直接聲明符
[
類型限定符列表opt*
]
- 直接聲明符
(
參數類型列表)
- 直接聲明符
(
標識符列表選項)
指針:
*
類型限定符列表選擇*
類型限定符列表選擇指針類型限定符列表:
- 類型限定符
- 類型限定符列表 類型限定符
參數類型列表:
- 參數列表
- 參數列表
,
...
參數列表:
- 參數聲明
- 參數列表
,
參數聲明參數聲明:
- 聲明說明符
- 聲明說明符抽象聲明符選擇
該語法需要一個直接聲明符標記來指定優先級。 事實上, * foo [ 3 ]
必須被解析為聲明符*
后跟一個直接聲明foo [ 3 ]
。 如果語法沒有將聲明符和直接聲明符分開,則可能不清楚這是*
后跟foo [ 3 ]
組合在一起還是* foo
后跟[ 3 ]
組合在一起。
語法說聲明符是:
其中指針是*
后跟可選的限定符(如const
),直接聲明符是以下之一:
(
聲明符)
[
類型限定符列表opt賦值表達式opt ]
[
static
類型限定符列表選擇賦值表達式]
[
類型限定符列表static
賦值表達式]
[
類型限定符列表opt * ]
(
參數類型列表)
(
標識符列表選項)
因此,給定* foo [ 3 ]
,我們必須將其作為聲明符, *
表示指針, foo [ 3 ]
表示直接聲明符。 無法在直接聲明符的開頭使用*
。 因此, * foo [ 3 ]
必須聲明一個包含 3 個指針的數組,而不是指向包含 3 個元素的數組的指針。
如果將declarator和direct-declarator的那些選項合並為一個語法標記,那么解析就會有歧義。 您可以將其解析為* foo [ 3 ]
因為* foo
是一個后跟[ 3 ]
的聲明符,這不是我們想要的。
名字並不重要; 我們只需要額外的令牌的另一個名稱。 在 C 語法中還有其他示例。 值得注意的是,表達式文法以表達式開始,然后經過一系列賦值表達式、條件表達式、邏輯或表達式等。 在您到達primary-expression之前,它們的名稱與它們涉及的運算符相關聯。 這與direct-declarator有一些語義相似性,表明它們都是本着“好的,我們到達了這個語法鏈的底部,這是主要/直接標記”的精神命名的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.