高建波 方芳 趙敏

[摘 要] 使用函數(shù)聲明可以避免在主函數(shù)之前定義所有的子函數(shù)。然而,函數(shù)聲明卻有很多細(xì)節(jié)需要關(guān)注,尤其是遇到函數(shù)之間嵌套調(diào)用時。為深入理解函數(shù)聲明,必須清楚程序編譯原理和編譯過程。該文通過一個C++例題的分析,詳細(xì)闡述函數(shù)聲明與編譯的關(guān)系,同時說明養(yǎng)成良好編程習(xí)慣的重要性。
[關(guān)鍵詞] 函數(shù)聲明;編譯;編程習(xí)慣
[作者簡介] 高建波,南昌航空大學(xué)信息工程學(xué)院講師,主要從事計算機(jī)科學(xué)與技術(shù)研究;方 芳,南昌航空大學(xué)信息工程學(xué)院講師,主要從事計算機(jī)科學(xué)研究;趙 敏,南昌航空大學(xué)信息工程學(xué)院講師,主要從事計算機(jī)科學(xué)研究。
[中圖分類號] G642.0? ? [文獻(xiàn)標(biāo)識碼] A? ? [文章編號] 1674-9324(2020)23-0135-02? ? [收稿日期] 2019-11-25
一般來說在編程時,子函數(shù)的定義可以放在主函數(shù)之前,也可以放在主函數(shù)之后。將子函數(shù)的聲明放在主函數(shù)之前,子函數(shù)的定義放在主函數(shù)之后,可以讓程序顯得更加直觀,這也是良好的編程習(xí)慣,而很多編程教學(xué)者和初學(xué)者并不重視這一點[1]。不好的編程習(xí)慣會導(dǎo)致很多錯誤,而這些錯誤在良好編程習(xí)慣下會自動屏蔽,因此有必要深入探討函數(shù)聲明,尤其是編程中遇到函數(shù)之間相互調(diào)用和嵌套調(diào)用時。為理解函數(shù)聲明的重要性,需要考慮編譯器的工作原理及其與函數(shù)聲明的關(guān)系[2]。
一、函數(shù)聲明和編譯
(一)編譯器和編譯
編譯器是C++程序的語法拼寫檢查器,當(dāng)一個程序被寫好并存儲后,就可以對它進(jìn)行編譯。這時編譯器程序就會對程序進(jìn)行詞法分析、語法分析、語義分析和中間代碼生成。在任何一個環(huán)節(jié)發(fā)現(xiàn)錯誤編譯器就會給出錯誤的報告清單。編譯器的工作中詞法分析的任務(wù)是從左到右、從上到下逐字符地讀入源程序,即對構(gòu)成源程序的字符進(jìn)行掃描然后根據(jù)構(gòu)詞規(guī)則識別單詞符號。語法分析的任務(wù)是在詞法分析的基礎(chǔ)上將單詞序列組合成各類語法短語并判斷程序在結(jié)構(gòu)上是否正確。語義分析的任務(wù)是對結(jié)構(gòu)上正確的源程序進(jìn)行上下文有關(guān)性質(zhì)的審查。接著編譯程序?qū)⒃闯绦蜃兂芍虚g代碼,一種結(jié)構(gòu)簡單、含義明確、易于翻譯成目標(biāo)代碼的的記號系統(tǒng)。
(二)函數(shù)聲明與編譯的關(guān)系
在編程時,程序員經(jīng)常將主函數(shù)放在程序的最前面,這樣程序看起來更加直觀。然而當(dāng)主函數(shù)中需要調(diào)用很多的子函數(shù)時,如果將子函數(shù)的定義均放在主函數(shù)之后,那么在程序編譯時就會報錯。報錯的原因在于編譯器在編譯程序時是從上至下進(jìn)行的,在調(diào)用子函數(shù)時,必須讓計算機(jī)知道這個程序中存在這么一個函數(shù),而將子函數(shù)定義在主函數(shù)之后,那么在對主函數(shù)進(jìn)行編譯時無法找到對應(yīng)的子函數(shù)。為解決這個問題,可以在主函數(shù)之前先聲明子函數(shù)的原型定義[3],以便讓編譯器知道函數(shù)的參數(shù)和返回值類型,在主函數(shù)之后再具體定義子函數(shù)的內(nèi)容。例如,
1.#include “stdafx.h”
2.#include
3.using namespace std;
4.void printmessage()
5.int main()
6.{ printmessage();
7.return 0;}
8.void printmessage()
9.{cout << “I'm a function!”;}
該程序第4行聲明了printmessage()函數(shù),該函數(shù)沒有形參和返回值,且在主函數(shù)的前面,程序的第8、9行定義了函數(shù)printmessage(),也即明確說明函數(shù)的功能。該程序亦可做如下的修改:將子函數(shù)printmessage()定義在主函數(shù)之前,即將程序的第8、9行放置于程序的第5行之前,并去掉程序的第4行。兩種方法都可以通過編譯,相比而言,第一種方法更符合良好編程習(xí)慣的要求。
二、子函數(shù)之間有嵌套調(diào)用時的函數(shù)聲明
上例中,子函數(shù)可以放在主函數(shù)之前或之后,因此編程者會忽視良好編程習(xí)慣。在遇到函數(shù)之間相互嵌套調(diào)用時,對子函數(shù)聲明的采用與否,則會產(chǎn)生完全不同的結(jié)果。
(一)一個嵌套調(diào)用的例子和相關(guān)說明
1.#include “stdafx.h”
2.#include
3.using namespace std;
4.void odd (int a) {
5.if ((a%2)!=0) cout << “Odd number.\n”;
6.else even (a);}
7.void even (int a) {
8.if ((a%2)==0) cout << “Even number.\n”;
9.else odd (a);}
10.int main () {
11.int i;
12.do {
13.cout << “Type a number: (0 to exit)”;
14.cin >> i;
15.odd (i);
16.} while (i!=0);
17.return 0;}
該程序的兩個子函數(shù)odd()和even()之間存在相互調(diào)用的情形。雖然將兩個子函數(shù)均定義在了主函數(shù)之前,然而因為編譯是從上至下執(zhí)行的,當(dāng)執(zhí)行到7行時odd()函數(shù)調(diào)用了even()函數(shù),而此時even()函數(shù)根本不存在。同理如果將even()函數(shù)定義放在odd()定義之前依然會遇到類似問題。在以上兩種情況下,該程序均無法通過編譯。而良好的編程習(xí)慣事先要求聲明所有子函數(shù),從而不會產(chǎn)生這種編譯錯誤。
(二)對上例的深入分析
為更加深入理解函數(shù)聲明和編譯之間的關(guān)系,設(shè)計了四個小程序片段,見表1。
這四個片段并不是完整的程序,卻可用來說明函數(shù)聲明和編譯關(guān)系。在片段1中,主函數(shù)之前聲明了子函數(shù)even(),由于在主函數(shù)的內(nèi)容調(diào)用了odd()函數(shù),而此時并沒有聲明odd()函數(shù),編譯器執(zhí)行到這里時直接報錯。在片段2中,函數(shù)even()中調(diào)用了odd(),而此時odd()并不存在,編譯器立刻報錯。在片段3中,先聲明函數(shù)odd(),然后在even()中進(jìn)行了調(diào)用,這是沒有問題的;同理,主函數(shù)也可以調(diào)用odd()函數(shù)。片段4中先聲明了函數(shù)odd(),然后主函數(shù)中調(diào)用odd(),再在even()函數(shù)中調(diào)用odd(),而函數(shù)odd()也調(diào)用了even(),因為even()定義在odd()之前,因此也沒有問題。雖然片段3和4可以通過編譯,然而先聲明子函數(shù)的方式顯得更加簡單和直觀,免去了分析子函數(shù)相互調(diào)用的細(xì)節(jié)。
三、結(jié)論
因為編譯器在編譯程序時是從上至下的,所以使用函數(shù)聲明可以避免子函數(shù)間相互調(diào)用而產(chǎn)生的編譯錯誤,而這也是良好的編程習(xí)慣。本文構(gòu)建了四個小程序片段,用于說明函數(shù)聲明和編譯的關(guān)系,從而加深對函數(shù)聲明及其重要性的理解。
參考文獻(xiàn)
[1]何雪英.C++教學(xué)中編程習(xí)慣的培養(yǎng)[J].電腦知識,2019,15(22):126-127,129.
[2]萬新燕,時招軍.編譯原理實驗教學(xué)設(shè)計[J].教育教學(xué)論壇,2019,2(8):261-262.
[3]保羅.斯奈思(著),劉繼飛等(譯).C++[M].沈陽:遼寧教育出版社,2002.
Discussion on the Relation Between Function Declaration and Compilation in C++
GAO Jian-bo,F(xiàn)ANG Fang,ZHAO Min
(Nanchang Institute of Information Engineering,Nanchang,Jiangxi 330000,China)
Abstract:Using function declaration can avoid defining all sub-functions before the main function.However,function declarations have many details to pay attention to,especially when it comes to nested calls between functions.In order to understand the function declaration in depth,we must make clear the principle of program compilation and the compiling process.This paper elaborates the relation between function declaration and compilation through a C++ example analysis,and explains the importance of developing good programming habits.
Key words:function declaration;compilation;programming habit