1. 程式人生 > >C語言中要求在使用識別符號之前宣告它們

C語言中要求在使用識別符號之前宣告它們

   C11標準要求宣告識別符號的型別,禁止隱式函式宣告,C90標準允許隱式的確定變數

和函式的型別。因此,一些現有的遺留程式碼使用隱式型別,一些C編譯器為了支援遺留

程式碼仍然允許隱式型別,但是新的程式碼不應該再使用。這樣的實現可以選擇使用隱式

宣告,並繼續翻譯,以支援使用這個特性的現有程式。

1、隱式int

C不再允許不指定型別的宣告,C11標準6.7.2節表示

  每個宣告的宣告指示符中至少應該有一個型別指示符。

異常程式碼例子:extern foo;

這個異常的例子省略了型別指示符,一些C翻譯器並不會在遇到違反這個約束

情況時產生診斷資訊,這些不合格的C翻譯器會繼續處理這類宣告,把型別

隱式的當做int。

修改後的例子:extern int foo;

2、隱式函式宣告

不允許隱式函式宣告,每個函式必須在呼叫前被顯式宣告。在C99標準中,

如果一個被呼叫的函式沒有顯示宣告原型,編譯器會為它提供一個隱式宣告。

C90標準包含了下面的需求:

  如果在一個函式呼叫中,帶括號的實參列表前面的表示式只由一個識別符號

 組成,並且看不到這個識別符號的宣告,這個識別符號將被隱式的宣告,就像在

 最內層的程式碼塊中包含了這個函式呼叫時出現了extern int identifier()這個宣告。

如果一個函式的宣告在被呼叫的地方不可見,C90相容平臺會為其假定一個隱式

宣告 extern int indentifier();

       這個聲明暗示這個函式可以取任何數量和型別的引數並返回一個int型資料。而如果

遵守當前C標準,程式設計師必須在每個函式呼叫前顯式的宣告函式原型。符合C標準的

應用可以遵守也可以不遵守隱式函式宣告,但是如果遇到使用未宣告的函式時,C需要

產生診斷資訊。

     在下面這個異常示例中,如果malloc()函式沒有被顯式宣告或被包含在stdlib.h中,只遵守

C90標準的編譯器會隱式宣告malloc()函式為int malloc()。如果系統平臺的int長度是32位,但是

指標長度是64位,那麼本例中的結果就會導致返回的指標被截斷,返回一個32位的整型。

#include <stddef.h>
/* #include <stdlib.h> is missing */

int main(void) {
 for (size_t i = 0; i < 100; ++i) {
     /* int malloc() assumed */
    char *ptr = (char *) malloc(0x10000000);
    *ptr = 'a';
    }
 return 0;
}

如果使用微軟Visual Studio 2013 64位編譯平臺,這個異常程式碼例子最終會導致一個非法

訪問錯誤。

修改後的程式碼為:

#include <stdlib.h>

int main(void) {
 for (size_t i = 0; i < 100; ++i) {
    char *ptr = (char *) malloc(0x10000000);
    *ptr = 'a';
    }
 return 0;
}

3、隱式返回型別

不要宣告具有隱式返回型別的函式,如果一個函式返回一個有意義的整型值,就把它的

返回型別宣告為int,如果返回無意義的值,就宣告為void。

  異常程式碼示例:

#include<limits.h>
#include<stdio.h>

foo(void) {
    return UINT_MAX;
 }

 int main(void) {
    long long int c = foo();
    printf("%lld\n", c);
    return 0;
}

因為編譯器假設foo()返回一個int 型別的值,因此UINT_MAX被不正確的轉換為-1.

修改後的程式碼為:

#include<limits.h>
#include<stdio.h>

unsigned int foo(void) {
    return UINT_MAX;
 }

 int main(void) {
    long long int c = foo();
    printf("%lld\n", c);
    return 0;
}

修改後的例子中,foo()返回型別被定義為unsigned int,因此函式正確返回了UINT_MAX.