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.