簡體   English   中英

為什么允許多次聲明typedef標識符?

[英]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不同

規則在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.

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