[英]main function can access function below it but not variable?
考慮以下代碼:
main()
{
func();
i = 8;
}
int i;
func()
{
}
我的主函數如何看到並調用func()但不能使用i,這也是在main下面定義的。
快速回答:不要這樣做。 應在使用前顯式聲明所有函數和變量。 早期版本的C允許您使用隱式聲明,但您不應該利用它。
在C89 / C90中(有時稱為“ANSI C”,但並不嚴格准確),如果調用沒有可見聲明的函數,則會創建一個隱式聲明,假設該函數返回int
並且接受(提升的)類型的參數通過電話。 對象沒有這樣的隱式聲明。
根據這個規則是一個壞主意。 如果函數實際返回的類型不是int
,或者它的參數與調用中傳遞的參數不匹配,則行為是未定義的,並且編譯器沒有義務告訴您出錯了。
所有被調用的函數在被調用之前都應該有一個顯式聲明,並且該聲明應該是一個原型 ,指定參數的類型。
1999 ISO C標准刪除了“隱式int
”規則,使得調用沒有可見聲明的函數成為非法(違反約束)。 (不幸的是,聲明不需要是原型,但你總是應該使用原型。)許多編譯器仍允許使用舊規則進行調用。 您應該了解如何讓您的編譯器至少警告這些調用。
這是您的程序的更正版本,在C89 / C90,C99和C11中有效:
void func(void);
int i;
int main(void)
{
func();
i = 8;
}
void func(void)
{
}
或者你可以簡單地將func
的定義移到main
的定義之上(除非你有遞歸調用,否則通常不需要“前向聲明”):
void func(void);
int i;
int main(void)
{
func();
i = 8;
}
void func(void)
{
}
在C中,調用未聲明的函數會觸發一些規則來構成返回值和參數的類型。 這是一個糟糕的想法,你應該始終啟用捕獲這個錯誤的編譯器警告。 傳遞或返回浮點值而不是int時,或者傳遞比int更寬的指針時,您將獲得破壞。
更好的是,讓您的編譯器處於C99或更高版本模式,而不是C89。 在C99中刪除了隱式聲明,因此您至少需要一個原型。
沒有前向聲明,沒有使用全局變量的規則。
在K&R C中,函數被隱式聲明返回int
並在沒有聲明時使用它們時接受任何參數。
省略返回類型也默認為返回類型為int
,因此定義不會與隱式聲明沖突。
從上到下解析源文件時,編譯器需要在使用之前查看所有標識符的聲明。 沒有顯式返回類型的函數的“隱式int”規則僅在C89 / 90中有效。 它已從C99中的標准中刪除。 因此func()
需要在C99及更高版本中使用原型。 如果您在C89 / 90模式下進行編譯,則函數func()
沒有錯誤。 GCC在C99模式下為您的代碼生成以下警告(沒有語句i=8
):
$gcc -Wall -Wextra -std=c99 file.c
warning: implicit declaration of function func
warning: return type defaults to int
即使在C89 / 90中,也不對變量i
執行這樣的隱式隱式聲明。 一個例外是函數參數。
例如,
int main(i)
{
func();
i = 8;
}
沒錯,因為i
默認在C89 / 90中輸入int
。 但它在C99及更高版本中無效。
為了使您的程序在現代C中有效,它應該是:
void func(); // (1) Prototype for func()
int main(void) // (2) return type of main() should be int
{
func();
extern int i; // (3) refers to the `i` tentatively defined after main()
i = 8;
}
int i;
void func()
{
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.