[英]Why are typedef identifiers allowed to be declared multiple times?
從C99標准來看,6.7(5):
聲明指定一組標識符的解釋和屬性。 標識符的定義是該標識符的聲明:對於對象,導致為該對象保留存儲; 對於一個功能,包括功能體; 對於枚舉常量或typedef名稱,是標識符的(唯一)聲明。
如果帶有typedef
標識符實際上是定義,那么為什么允許它們被多次聲明? 例:
int main()
{
typedef int x;
typedef int x;
}
上面的程序編譯沒有錯誤。 這怎么可能? 我期待該程序給我一個多重定義錯誤。
規則在C99和C11之間變化(並且C11規則與C ++規則匹配,據我所知)。 請注意,在這兩個標准中,¶3在Constraints部分中,¶5在Semantics部分中。 這對於錯誤消息很重要 - 約束違規需要診斷。
ISO / IEC 9899:1999§6.7聲明
¶3如果標識符沒有鏈接,則除了6.7.2.3中規定的標記之外,標識符(在聲明符或類型說明符中)的聲明不應超過一個具有相同作用域和相同名稱空間的聲明。
5聲明指定一組標識符的解釋和屬性。 標識符的定義是該標識符的聲明:
- 對於一個對象,導致為該對象保留存儲;
- 對於一個函數,包括函數體; 98)
- 對於枚舉常量或typedef名稱,是標識符的(唯一)聲明。
ISO / IEC 9899:2011§6.7聲明
¶3如果標識符沒有鏈接,則標識符的聲明(在聲明符或類型說明符中)不得超過一個具有相同作用域和相同名稱空間的聲明,但以下情況除外:
- 如果類型不是可變修改類型,則可以重新定義typedef名稱以表示與其當前相同的類型;
- 標簽可以按照6.7.2.3中的規定重新聲明。
¶5聲明指定一組標識符的解釋和屬性。 標識符的定義是該標識符的聲明:
- 對於一個對象,導致為該對象保留存儲;
- 對於一個函數,包括函數體; 119)
- 對於枚舉常量,是標識符的(唯一)聲明;
- 對於typedef名稱,是標識符的第一個(或唯一的)聲明。
Lundin 指出 ,標准C委員會的網站包含n1360 ,這是一份單頁文件,詳細說明了為何進行此項更改。 基本上:C ++就是這樣做的; 一些編譯器已經做到了; 既不難做也不顛覆任何東西以允許(要求)它。
如果您的代碼正在編譯,那么它將根據C11規則或C ++規則進行編譯。 它不是根據(嚴格)C99規則編譯的。
請注意,除非您另有說明,否則GCC的最新版本允許重新定義,但也請注意John Bollinger的報告 ,即GCC 4.4.7(在未識別的平台上)不允許在C99模式下重新定義。
考慮文件retypedef.c
:
int main(void)
{
typedef int x;
typedef int x;
x y = 0;
return y;
}
使用GCC 4.9.1在Mac OS X 10.9.5上進行編譯,得到:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -c retypedef.c
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -pedantic -c retypedef.c
$ gcc -O3 -g -std=c99 -Wall -Wextra -Werror -c retypedef.c
$ gcc -O3 -g -std=c99 -Wall -Wextra -Werror -pedantic -c retypedef.c
retypedef.c: In function ‘main’:
retypedef.c:4:17: error: redefinition of typedef ‘x’ [-Werror=pedantic]
typedef int x;
^
retypedef.c:3:17: note: previous declaration of ‘x’ was here
typedef int x;
^
cc1: all warnings being treated as errors
$
除非使用-pedantic
,否則它不會抱怨,只有在請求C99時才符合要求(在C11中重新定義同一范圍內的typedef
是標准的)。
您的程序編譯沒有錯誤,因為您的編譯器是松散的(或編譯為不同的標准)。 如果我使用gcc 4.4.7編譯你的代碼,那么它實際上確實報告了關於x的重新定義的錯誤。
出於同樣的原因,允許多次聲明其他聲明。 例如:
void foo(int a);
void foo(int a);
int main()
{
foo(42);
}
void foo(int a)
{
printf("%d\n", a);
}
這允許多個頭部聲明一個函數或結構,並允許兩個或多個這樣的頭部包含在同一個轉換單元中。
typedef類似於原型化函數或結構 - 它們聲明具有一些編譯時間含義的標識符,但沒有運行時含義。 例如,以下內容無法編譯:
int main()
{
typedef int x;
typedef int x;
x = 42;
}
因為x
沒有命名變量; 它只是名稱int
的編譯時別名。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.