第六章 C++/C函數設計基礎 =====高質量程序設計指南 林銳

認識函數:

               1.使用一直語言實現時,應該瞭解它提供哪些庫,如庫函數,類庫,系統調用等。儘量使用庫函數,避免重複勞動

                2.靜態鏈接庫:連接器會從相應的庫中提取這些函數的實現代碼把她們鏈接到你的程序中,若沒有調用,連接器是不會把實現代碼鏈接進來的。

                   動態鏈接庫:DDL 運行時將所有的DDL都複製到運行環境的相應目錄下。

   
 注意:我們在開發一些通用類的時候,應該設計並實現完整的功能,而不許要去擔心它的使用者會因爲僅僅使用其中的一小部分功能卻要包含整個文件導致代碼體積增大。


函數調用:

                 用實參來初始化形參,而不是替換形參。應該在原型中寫出形參名稱,雖然編譯器會忽略它們,這樣做使函數具有“自說明”和“自編檔”能力。

                 調用方式:過程調用,嵌套調用,遞歸調用。 回調函數

            

                   回調函數:事件驅動程序and多線程應用程序中很常見。典型例子:系統定時器回調函數和線程函數

                             特點:線程函數不使用普通的函數堆棧,而使用線程自己的堆棧,線程堆棧是線程在每次啓動時動態分配的,這就可以在每次使用時使用不同的堆棧,從而避免線程函數執行流重疊時出現的一些堆棧破壞。此外,若一個函數可能被多個線程調用的話,對於他們共享的數據進行同步訪問,避免使用static局部變量。


函數堆棧:

              函數堆棧使用的是程序的堆棧段內存空間,雖然程序的堆棧段是系統系統爲程序分配的一種靜態數據區,但是卻是在調用到它的時候才動態分配。

              不能在編譯時爲函數分配好堆棧 1 因爲無法在編譯時確定一個函數運行時所需的堆棧大小 2 函數調用完畢不釋放內存導致內存浪費

               堆棧是自動管理的,即局部變量的創建和銷燬,堆棧的釋放都是函數自動完成的,不需要程序員的干涉。這就是堆棧與堆和自由存儲空間的區別(能否顯式的分配和釋放)。

              函數堆棧的三個用途:在進入函數前保存環境變量和返回地址,在進入函數時保存實參的拷貝,在函數體內保存局部變量。


函數調用規範:

                    決定了函數調用的實參壓棧,退棧及堆棧釋放的方式,以及函數名改編的方案。

                      1.——caecl:C++/c函數默認調用規範,參數從右往左依次傳遞壓入堆棧,由調用函數負責堆棧清退,該方式利於傳遞可變參數給被調用函數,因爲只有調用函數才知道它應該給被調用函數傳幾個參數),比如printf()

                       2.——stdcall:Win API函數使用的調用規範,參數從右往左依次傳遞壓入堆棧,由被調用函數負責棧的清退,生成的函數代碼比_caecl更小,當有可變參數時自動轉爲_caecl規範。

                        3.——thiscall:C++非靜態成員函數調用方式,不能使用個數可變的參數,當調用非靜態成員函數時,this指針直接保存在ECX寄存器中而非壓入函數堆棧。其他的與_stdcall相同。

                        4.——fastcall:該規範所修飾的函數實參將被直接傳遞到CPU寄存器中,而非堆棧,這就是快速調用的含義,堆棧請退由被調用函數負責。不能用於成員函數。

函數必須指定一個調用規範,否則會出現編譯錯誤。


參數傳遞規則:

                       1.傳值調用,2傳址調用 3.引用傳遞

                      規則1:函數原型定義明確寫出每個參數的類型和名字,若函數沒有參數,應使用void不要空着,因爲標準C把空的參數列表解釋爲可以接受任何類型和個數的參數,標準C++則把空的參數列表解釋爲不可以接受任何參數。移植時需要注意!

                     規則2:參數命名要恰當,輸入參數輸出參數的順序要合理,避免參數過多,可以考慮用對象封裝

                     規則3:若參數爲指針,只做輸入用,應該加const,防止修改。

       

返回值的規則:

                       規則1:不要省略返回值類型,標準C省略默認返回int,容易誤解爲void C++明確必須有返回值類型

                       規則2:函數名字與返回值類型在語義上不可衝突,char c=getchar();//error int getchar(void)

                      規則3:有時候函數原本不需要返回值,但是爲了增加靈活性,支持鏈式表達,char *strcpy(char* strDest,char* strSrc), strlen(strcpy(str,"helloworld"));

                      規則4:返回值是一個對象,可以返回引用替換返回對象值,提高效率,支持鏈式表達0


函數的內部實現規則:

                      函數入口:對參數的有效性進行檢查。使用斷言assert來防止此類錯誤

                       函數出口:對return 語句的正確性和有效性進行檢查。

                      不能返回局部變量的地址和引用。

                      返回臨時對象:避免構造析構函數的開銷,提高了效率

                       返回臨時變量: return (x+y);而不是 temp=x+y;return temp;

                    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章