1. 程式人生 > >C語言中,函式不宣告也能使用,但會出現warning: implicit declaration of function

C語言中,函式不宣告也能使用,但會出現warning: implicit declaration of function

偶然發現有很多自定義函式未經宣告卻能在主程式中被呼叫,這就奇怪了,連使用標準庫函式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;
}
程式正常執行,因為Max()在被呼叫前已經定義。
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);
}
程式正常執行,因為Max()在被呼叫前已經定義。


二、在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.c
gcc -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]# ./test2
Please 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。

相關推薦

C言中函式宣告使用出現warning: implicit declaration of function

偶然發現有很多自定義函式未經宣告卻能在主程式中被呼叫,這就奇怪了,連使用標準庫函式printf()都要包括標準輸入輸出標頭檔案<stdio.h>,何況是自定義函式?這個問題困擾了我很久。 今天通過實驗,基本明白了箇中原因。一、在VC6中, 1、檔案test1.

c言中printf函式列印char型變數0xFF輸出為0xFFFFFFFF的解決方法

問題描述:在編寫udp程式解析資料的時候,發現接收的char型變數為0xFF,但是使用printf後列印為0xFFFFFFFF,除錯程式查詢原因後發現使用char時,對於printf來說其值為0xFFFFFFFF。原因是%x要求的是無符號整形變數,你傳入的是char型,這裡有

C言中static 函式除了再外部被呼叫外和普通函式還有什麼區別呢?

iThinks:本文來自CSDN論壇的討論,觀點不一定全對,但值得從這幾個方面考察static。 C程式一直由下列部分組成:       1)正文段——CPU執行的機器指令部分;一個程式只有一個副本;只讀,防止程式由於意外事故而修改自身指令;      2)初始化資料段

c言中getchar函式的用法涉及EOF檔案結束符的問題

 最近因為遇到了這個EOF的問題就查了下,一下的這些內容幫助我解決了困惑已久的問題,寫在這個希望能夠幫助遇到同樣問題的朋友!       在C語言中有個重要的庫函式getchar(),可從終端獲得一個字元的ASCII碼值。在終端輸入字元時並非輸入一個字元就會返回,而是在遇到

c言中 gotoxy() 函式的使用

轉自  https://blog.csdn.net/radjedef/article/details/79028329 #include <stdio.h> #include <windows.h> void gotoxy(int x, int y) {

關於C言中printf函式“輸出歧視”的問題

目錄 關於C語言中printf函式“輸出歧視”的問題 問題描述 探索問題原因 另一種研究方法 問題結論 關於C語言中printf函式“輸出歧視”的問題 問題描述 昨天晚上被問到一個問題,為什麼在同一個printf函式中兩次輸出一個double型變

c言中rand()函式的用法筆記

最近在學著用c寫一些小程式,過程中遇到很多問題,在網上查很多大神的講解,以及查閱vs2010的幫助文件。在此做個筆記,以便今後查閱,備忘。感謝無私奉獻講解的大神們! 一、rand() rand()函式用來產生隨機數,但是,rand()的內部實現是用線性同餘法實現的,是偽隨機數,由於週期較長,

(C言中printf函式讀取的具體分析)

(C語言中printf函式讀取的具體分析) 不多說,直接上。printf函式將傳入的資料傳送到記憶體堆區(緩衝區),然後再根據前面的(格式說明符一個個讀取,這樣會造成錯誤) #include<stdio.h> #include<limits.h> #incl

C言中main函式引數使用

在C99標準中定義main函式兩種正確的寫法 int main(void); int main(int argc, char* argv[]); 常見的不標準寫法 void main() main()

C言中strlen函式的模擬實現n種方法

strlen 函式採用遞迴形式編寫 # include <stdio.h> # include <stdlib.h> int strlen (char* num) // 形參接受實參傳遞的陣列 {

C言中scanf函式輸入回車符的問題

 在用c語言編寫輸入語句的時候常用到scanf函式,初學者在剛用scanf函式輸入時,經常會遇到各種各樣的輸入錯誤,最重要的是一定要記住scanf函式的輸入格式,scanf函式裡包含了哪些東西,輸入的時候就必須有哪些東西,比如:scanf("%c%c%c"),那麼輸入的時

C言中 main 函式的引數 argc&argv

argc、argv用命令列編譯時有用 argc:整數 srgv:二維陣列、指標的指標、指標陣列 例子 #include<stdio.h> #include<stdlib.h> int main(int argc, char** argv) { i

c言中get()函式的原理及返回值

首先要記住的一句話就是Never use gets(). 這是因為gets()函式不檢查目標陣列是否能夠容納輸入,而若想把一個字串讀到程式中,最先要做的事情就是預留儲存字串的空間。所以這很容易導致分配的空間不夠大而陣列越界,然而gets()函式並不檢查這個方面,所以導致的結

C言中assert函式的用法

  2)每個assert只檢驗一個條件,因為同時檢驗多個條件時,如果斷言失敗,無法直觀的判斷是哪個條件失敗   不好: assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);   好:  assert(nOffset >

c言中getchar()函式一個常見Error

getchar() 從這個名字來看應該是 得到一個字元。 正好C語言裡面有一個char型別, 很容易就出現瞭如下程式: # include <stdio.h> int main (voi

c言中signal函式詳細解釋說明

對於 訊號處理函式 位於 <signal.h> 中.void ( *signal( int sig, void (* handler)( int ))) ( int );這個函式的宣告很是嚇人, 一看就難弄懂. 下面是解釋用法.一步一步解釋:int (*p)();這是一個函式指標, p所指向的函

C言中fopen函式用法詳解

fopen函式用來開啟一個檔案,其呼叫的一般形式為:檔案指標名=fopen(檔名,使用檔案方式); 其中,“檔案指標名”必須是被說明為FILE 型別的指標變數;“檔名”被開啟檔案的檔名,是字串常量或字串陣列,要求是全路徑;“使用檔案方式”是指檔案的型別和操作要求。 檔案使用方

14.C言中time函式和localtime獲取系統時間和日期

C語言中time函式和localtime獲取系統時間和日期可以通過time()函式來獲得計算機系統當前的日曆時間(Calendar Time),處理日期時間的函式都是以本函式的返回值為基礎進行運算。1. time 函式 返回1970-1-1, 00:00:00以來經過的秒數 

關於C言中printf函式的引數執行順序

RT...看到有類似的題目,說是從右到左,, 藍後在VS2012中寫了如下的程式碼...但是執行出來的結果如下,, 這是為啥...  留一疑惑在這先. ok,這裡有了一個解釋: i++會建立一個拷貝 %d取值輸出,引數的傳遞是從右到左壓入棧,所以從右邊開始,i++,此時拷貝

C言中atoi()函式實現--字串轉int型整數

C語言中有個atoi()函式,將字串轉成整數,返回int型別的數值。思路很簡單,但是有很多邊界和細節要處理,本文參考劍指offer上的例項,僅供參考。 #include <iostream&