C語言中,函式不宣告也能使用,但會出現warning: implicit declaration of function
阿新 • • 發佈:2019-02-04
偶然發現有很多自定義函式未經宣告卻能在主程式中被呼叫,這就奇怪了,連使用標準庫函式printf()都要包括標準輸入輸出標頭檔案<stdio.h>,何況是自定義函式?這個問題困擾了我很久。
今天通過實驗,基本明白了箇中原因。一、在VC6中,
1、檔案test1.cpp如下:
#include "stdafx.h" // stdafx.h: #include <stdio.h> int Max(int x, int y) { return ((x > y ) ? x : y); } int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; }
2、將Max()移到main()之後:
#include "stdafx.h" // stdafx.h: #include <stdio.h> int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; } int Max(int x, int y) { return ((x > y ) ? x : y); }編譯時出錯:
error C2065: 'Max' : undeclared identifier
error C2373: 'Max' : redefinition; different type modifiers
3、在main()之前新增Max()的宣告:
#include "stdafx.h" // stdafx.h: #include <stdio.h> int Max(int x, int y); int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; } int Max(int x, int y) { return ((x > y ) ? x : y); }
二、在Linux中,
1、檔案test2.c如下:
#include <stdio.h> int Max(int x, int y) { return ((x > y ) ? x : y); } int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; }用gcc編譯:gcc -Wall -o test2 test2.c,通過。程式正常執行,因為Max()在被呼叫前已經定義。
2、將Max()移到main()之後:
#include <stdio.h> int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; } int Max(int x, int y) { return ((x > y ) ? x : y); }
用gcc編譯:gcc -Wall -o test2 test2.c,出現警告:
warning: implicit declaration of function `Max'仍然編譯通過,程式也能正常執行,因為在C語言中,當函式在呼叫函式之前沒有宣告或定義,預設作為隱式宣告處理,只要在呼叫函式之後定義,或在別的模組中定義並編譯成庫檔案,該庫檔案在呼叫函式所屬模組編譯時載入,程式即可正常執行。
用g++編譯:g++ -Wall -o test2 test2.c,出現錯誤和警告:
error: `Max' was not declared in this scope
warning: unused variable 'Max'
沒有生成可執行程式test2。因為g++使用C++的規則:函式在被呼叫前必須宣告或定義。
三、在Linux中,採用實際工程的方式(分成若干模組)進一步實驗,驗證了C語言中函式在被呼叫前不申明也能使用。
1、在/u01/work/tools目錄中,編寫4個檔案:Max.c:
int Max(int x, int y) { return ((x > y ) ? x : y); }
Min.c:
int Min(int x, int y) { return ((x > y ) ? y : x); }
Add.c:
int Add(int x, int y) { return (x + y); }
Makefile:
#User defined library, by He Yaozhong CC=gcc HOME=/u01/work OS=$(HOME)/tools INCLUDE=$(HOME)/headfile -I$(HOME)/tools CSTARGETS=Max.o Min.o Add.o LIBS=$(HOME)/lib/tools.a all: $(LIBS) clean Max.o : Max.c $(CC) -I$(INCLUDE) -c $(CCFLAGS) Max.c Min.o : Min.c $(CC) -I$(INCLUDE) -c $(CCFLAGS) Min.c Add.o : Add.c $(CC) -I$(INCLUDE) -c $(CCFLAGS) Add.c $(LIBS) : $(CSTARGETS) cd $(OS); / ar ruv $(LIBS) $(CSTARGETS:$HOME/lib/=) clean: rm -f *.o
在/u01/work/tools目錄中,使用make工具:
[[email protected] tools]# make
gcc -I/u01/work/headfile -I/u01/work/tools -Wall -c Max.cgcc -I/u01/work/headfile -I/u01/work/tools -Wall -c Min.c
gcc -I/u01/work/headfile -I/u01/work/tools -Wall -c Add.c
cd /u01/work/tools; /
ar ruv /u01/work/lib/tools.a Max.o Min.o Add.o
r - Max.o
r - Min.o
r - Add.o
rm -f *.o
生成了/u01/work/lib/tools.a庫檔案。
2、在/u01/work/test2目錄中,編寫2個檔案:
test2.c:#include <stdio.h> int main(int argc, char* argv[]) { int a, b; printf("Please input 2 integer (a, b): /n"); scanf("%d", &a); scanf("%d", &b); printf("Max(a, b): %d/n", Max(a, b)); printf("Min(a, b): %d/n", Min(a, b)); printf("Add(a, b): %d/n", Add(a, b)); return 0; }
Makefile:
CC=gcc HOME=/u01/work INCLUDE=-I$(HOME)/headfile -I. CFLAGS= -L$(HOME)/lib LIBS=$(HOME)/lib/tools.a all : $(OBJS) test2 clean test2 : test2.c $(CC) $(INCLUDE) -Wall -o test2 test2.c $(CFLAGS) $(LIBS) clean : rm -f *.o
在/u01/work/test2目錄中,使用make工具:
[[email protected] func_pointer]# make
gcc -I/u01/work/headfile -I. -Wall -o test2 test2.c -L/u01/work/lib /u01/work/lib/tools.a
test2.c: In function `main':
test2.c:11: warning: implicit declaration of function `Max'
test2.c:12: warning: implicit declaration of function `Min'
test2.c:13: warning: implicit declaration of function `Add'
rm -f *.o
生成了/u01/work/test2/test2可執行檔案。執行程式:
[[email protected] func_pointer]# ./test2Please input 2 integer (a, b):
200
300
Max(a, b): 300
Min(a, b): 200
Add(a, b): 500
結果完全正確。
四、小結
C和C++是強型別語言,變數型別均應在程式碼執行前確定。在函式宣告方面C和C++則不同,C++語言中,在被呼叫之前未宣告或定義是不允許的,而C語言是允許的。初看起來C語言這一特性是靈活、省事,但缺點是:
1、程式可讀性差。
2、易出錯。函式先宣告再呼叫,是一種糾錯機制,如果不宣告,則沒有用到這種糾錯機制,雖然編譯、連線通過,程式也能執行,但很可能結果不正確。
一個好的程式設計師,應該養成嚴謹、規範的程式設計習慣,編譯程式時應開啟顯示所有警告選項“-Wall”,並且對編譯器提出的所有警告都要給予處理,僅以編譯、連線通過為目標,這可能會有潛在的危害。
五、筆記
本篇部落格的意義在第四部分的總結已經寫得很詳細了,我看這篇部落格的時候,對於第三部分涉及到makefile的模組編譯沒有看懂,因為makefile的語法不太懂,回頭有時間再試驗一下;
這兒重點說下 -I(大寫的i)引數,關於這個引數的使用在之前的部落格中我有提到,見:Linux下編譯多個不同目錄下的檔案以及靜態庫、動態庫的使用,對於本篇文章,也提到了-I引數,和之前是同樣的用法——指定編譯器搜尋標頭檔案的路徑。不同的是這兒在主函式中沒有include應有的標頭檔案,所以在編譯的時候有warning。