如何寫好一個(gè)函數(shù)_第1頁(yè)
如何寫好一個(gè)函數(shù)_第2頁(yè)
如何寫好一個(gè)函數(shù)_第3頁(yè)
如何寫好一個(gè)函數(shù)_第4頁(yè)
如何寫好一個(gè)函數(shù)_第5頁(yè)
已閱讀5頁(yè),還剩70頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、如何寫好一個(gè)函數(shù)課程目標(biāo)1開(kāi)啟嚴(yán)謹(jǐn)?shù)木幋a思維習(xí)慣軟件設(shè)計(jì)是一種追求完美的過(guò)程代碼與設(shè)計(jì)同等重要,都要精雕細(xì)刻軟件工程師的基本職業(yè)素養(yǎng):嚴(yán)謹(jǐn)、細(xì)致、不怕麻煩課程目標(biāo)2功能正確,達(dá)到效率要求遵循范式,直觀明了,簡(jiǎn)潔易讀具有好的可維護(hù)性,可調(diào)試性足夠健壯,達(dá)到安全要求討論優(yōu)質(zhì)代碼編寫的范式,明確代碼質(zhì)量的改進(jìn)目標(biāo)寫好代碼所必備的專業(yè)基礎(chǔ)計(jì)算機(jī)硬件架構(gòu)C語(yǔ)言模型與編譯原理操作系統(tǒng)原理數(shù)據(jù)結(jié)構(gòu)與算法函數(shù)的分解功能說(shuō)明返回值函數(shù)命名參數(shù)列表參數(shù)校驗(yàn)變量聲明與初始化功能語(yǔ)句返回值的初始化與函數(shù)返回功能說(shuō)明功能說(shuō)明最好一句話就能說(shuō)清楚,否則就拆分成多個(gè)函數(shù)列出函數(shù)調(diào)用者要注意的事項(xiàng),包括先決條件、空間時(shí)間資源

2、、資源的釋放、異常的處理等等用統(tǒng)一的書(shū)寫格式,且總是使功能說(shuō)明與函數(shù)實(shí)現(xiàn)保持一致/該函數(shù)實(shí)現(xiàn)如下功能/1、實(shí)現(xiàn)功能a/2、實(shí)現(xiàn)功能b/3、實(shí)現(xiàn)功能cvoid fun_a_b_c() /功能a . /功能b . /功能c ./該函數(shù)實(shí)現(xiàn)功能avoid fun_a()/該函數(shù)實(shí)現(xiàn)功能bvoid fun_b()/該函數(shù)實(shí)現(xiàn)功能cvoid fun_c()/函數(shù)調(diào)用者負(fù)責(zé)釋放資源CSomeObject* CreateSomeObject() ./以阻塞方式調(diào)用內(nèi)核I/O操作,調(diào)用者考慮性能int ReadDataFromSomeDevice( unsigned char* buf, int buf_si

3、ze) .返回值返回值的類型要慎重考慮,在保證精度的前提下盡量避免函數(shù)調(diào)用者對(duì)返回值做類型轉(zhuǎn)換int read_a_char() .void func() . char c = read_a_char(); .按值返回:函數(shù)返回過(guò)程中要執(zhí)行一個(gè)拷貝動(dòng)作才能將值傳遞給調(diào)用者,一般用于返回一個(gè)CPU寄存器就能裝下的值按地址返回:函數(shù)返回的是指向目標(biāo)的指針,常用于返回一個(gè)CPU寄存器裝不下的值函數(shù)調(diào)用者使用任何從子函數(shù)返回的地址值之前,必須先做有效性判斷void save_data(void* buf, int buf_size) FILE* fp; fp = fopen(“c:data.bin”,

4、 ”w+b”); fwrite(fp, buf, 1, buf_size); fclose(fp);bool save_data(void* buf, int buf_size) FILE* fp = 0; int file_size = 0; fp = fopen(“c:data.bin”, “w+b”); if (0 != fp) file_size = fwrite(fp, buf, 1, buf_size); if (0 != fclose(fp) file_size = 0; return (buf_size = file_size);函數(shù)的命名命名是程序員的一項(xiàng)基本功,優(yōu)秀的程序員

5、總是有意識(shí)的訓(xùn)練自己的命名水平準(zhǔn)確直觀描述函數(shù)的功能,如果函數(shù)的功能發(fā)生了變化,函數(shù)名必須作出相應(yīng)調(diào)整參考原則:縮寫風(fēng)格一致,不要有的地方縮寫有的地方不縮寫杜絕使用意義太泛的單詞,發(fā)現(xiàn)同義單詞立即替換成相同單詞/判斷一個(gè)目錄是否存在bool IsDirExist(const char* dir);/如果目錄不存在就創(chuàng)建該目錄bool MakeDirIfNotExist(const char* dir);動(dòng)賓格式詢問(wèn)格式事件響應(yīng)格式函數(shù)命名的幾個(gè)參考范式void HandleSyncMessage(UMessage* p_msg);void MailToParent(int aCode, int

6、 aParm);bool IsGraphObject();bool IsFirstSibling();void OnMouseMove(UMessage* p_msg);void OnSystemReadyToShutDown();參數(shù)列表形參的命名要直觀合理選擇傳遞方式void* MemCpy(void* p1, void* p2, int size);void* MemCpy(void* p_src, void* p_dst, int size);void func(BYTE a_table256);void func(BYTE* p_table, int table_size);合理安排

7、參數(shù)的順序int MemCmp(BYTE* buf1, BYTE* buf2);int MemCmp(BYTE* buf1, BYTE* buf2, int len1, int len2);int MemCmp(BYTE* buf1, int len1, BYTE* buf2, int len2);控制參數(shù)的個(gè)數(shù)int StretchDIBits(HDC hdc,int XDest,int YDest, int nDestWidth, int nDestHeight, int XSrc, int YSrc, int nSrcWidth, int nSrcHeight, CONST VOID *

8、lpBits, CONST BITMAPINFO *lpBitsInfo, UINT iUsage,DWORD dwRop);重要參數(shù)用注釋加以說(shuō)明參數(shù)要完備bool GetPathAndName( const char* szFullPathFileName, char* p_path, char* p_name);bool GetPathAndName( const char* szFullPathFileName, char* p_path, int max_path_size, char* p_name, int max_name_size);void WirteDataToSomeD

9、eivce( BYTE* p_buf, /必須是4字節(jié)對(duì)齊的地址 int buf_size);不要用參數(shù)控制函數(shù)內(nèi)部的執(zhí)行路徑void DoSomeLongProcs() /proc a . /proc b . /proc c . .隨著時(shí)間的流失,情況發(fā)生了變化,某次bug修正代碼被人改成如下:void DoSomeLongProcs( bool b_proc_a, bool b_proc_b, bool b_proc_c) if (b_proc_a) /proc a . if (b_proc_b) /proc b . if (b_proc_c) /proc c . void DoProcA

10、() /proc a .void DoProcB() /proc b .void DoProcC() /proc c .弊端:負(fù)責(zé)任的函數(shù)調(diào)用者總是要閱讀函數(shù)的實(shí)現(xiàn)代碼以確保傳入了正確的參數(shù),不負(fù)責(zé)任的函數(shù)調(diào)用者總是會(huì)埋下定時(shí)炸彈!函數(shù)說(shuō)明文檔的典范參數(shù)的校驗(yàn)要養(yǎng)成在函數(shù)的開(kāi)頭校驗(yàn)參數(shù)的習(xí)慣,增加軟件的健壯性,盡早暴露錯(cuò)誤,減小因錯(cuò)誤延遲暴露帶來(lái)的代價(jià)參數(shù)校驗(yàn)的方式:條件語(yǔ)句和斷言使用條件語(yǔ)句檢驗(yàn)參數(shù)的場(chǎng)合:無(wú)法保證函數(shù)調(diào)用者傳入的實(shí)參總是有效,例如模塊對(duì)外接口和工具函數(shù)或類的接口bool UDir:ReName(const char* p_old_name const char* p_new

11、_name) if (0 = p_old_name | 4 strlen(p_old_name) | 0 = p_new_name | 4 strlen(p_new_name) m_nErrorCode = FS_PARAM_ERROR; return false; .使用斷言校驗(yàn)參數(shù)的場(chǎng)合:設(shè)計(jì)上已經(jīng)保證了實(shí)參的有效性,對(duì)實(shí)參進(jìn)行校驗(yàn)的目的是為了捕捉或暴露編碼實(shí)現(xiàn)上問(wèn)題void UCineMem:PutData(const void* p_src, int page_size) ASSERT(NULL != p_src); ASSERT(m_PageSize = page_size); .b

12、ool UCineMem:GetData(void* p_dst, int page_size) ASSERT(NULL != p_dst); ASSERT(m_PageSize = page_size); .條件判斷和斷言同時(shí)使用的場(chǎng)合:條件判斷確保程序不會(huì)進(jìn)入異常狀態(tài),斷言用于捕捉出錯(cuò)現(xiàn)場(chǎng)bool DoSomeCriticalJob( void* p_buf, int buf_size) ASSERT(0 != p_buf); ASSERT(0 = buf_size) return false; .變量的聲明考慮符號(hào)void func() unsigned long a; unsigned

13、 long b; unsigned long c; a = GetA(); b = GetB(); c = GetC(); if (a b c) . 考慮精度f(wàn)loat CalcData(int a, int b, int c) float result = float(a * b) / float(c); return result;考慮內(nèi)存大小void func() short data = 0; fwrite(fp, &data, 1, sizeof(short); .內(nèi)存字節(jié)對(duì)齊的要求void IO_Write( BYTE* buf, /要求四字節(jié)對(duì)齊 int buf_size);vo

14、id func() . static const int BUF_SIZE = 1024; long bufBUF_SIZE / sizeof(long); . IO_Write(BYTE*)(&buf0), BUF_SIZE); .考慮跨平臺(tái)的要求/file: data_type.h#ifndef _DATA_TYPE_H_#define _DATA_TYPE_H_typedef unsigned char uint8;typedef unsigned short uint16;typedef unsigned long uint32;typedef unsigned long long u

15、int64;#endif考慮空間和時(shí)間性能,堆棧內(nèi)少用大數(shù)組和大尺寸對(duì)象void DoMathAlgorithm(int* numbers) int buf1024; . DoMathAlgorithm(buf) .嚴(yán)格初始化每一個(gè)變量,時(shí)刻警惕內(nèi)存溢出和內(nèi)存泄露void func() int* p_buf; . if (some condition) p_buf = new intBUF_SIZE; . if (0 != p_buf) delete p_buf; 精確把握變量在進(jìn)程中的地址空間和它們的生命周期堆棧(自動(dòng))變量:開(kāi)始于”, 終止于”靜態(tài)變量:程序鏈接過(guò)程中其邏輯地址就確定下來(lái)了

16、堆(內(nèi)存池)變量:開(kāi)始于new, 終止于delete順序結(jié)構(gòu)-運(yùn)行時(shí)無(wú)時(shí)序要求運(yùn)行時(shí)無(wú)時(shí)序要求不意味可以任意擺放代碼行,應(yīng)該力求按照統(tǒng)一的規(guī)則安排代碼行的順序,使得代碼容易維護(hù)變量的初始化變量的更新變量的聲明這三塊代碼嚴(yán)格遵循了一致的順序,使得代碼容易閱讀容易維護(hù),減少了筆誤的可能,即使發(fā)生了筆誤查找起來(lái)也容易!組織代碼使它們的依賴關(guān)系明顯子程序的名字應(yīng)當(dāng)清楚的表明依賴關(guān)系順序結(jié)構(gòu)-運(yùn)行時(shí)有時(shí)序要求使用子程序參數(shù)使依賴關(guān)系明顯注明不明確的依賴關(guān)系if-else分支結(jié)構(gòu)把正常的情況放在if后面而不是else后面,條件語(yǔ)句要少用非邏輯if (!condition) /do job Aelse /d

17、o job Bif (condition) /do job Belse /do job A多層if/else嵌套目標(biāo)要明確,盡快的到達(dá)最內(nèi)層的目標(biāo)邏輯if (condition1) if (condition2) if (condition3) /目標(biāo)邏輯 else . else . else .if (!condition1) .else if (!condition2) . else if (!condition3) . else /目標(biāo)邏輯 條件語(yǔ)句不怕括號(hào)多,就怕缺省運(yùn)算優(yōu)先級(jí)理解錯(cuò);復(fù)雜組合條件的邏輯值要預(yù)先生成好void func() bool cond1 = .; bool co

18、nd2 = .; bool cond3 = .; bool cond4 = .; bool judge = (cond1 | cond2) & (cond3 | cond4); if (judge) . else . .檢查各邏輯是否完全覆蓋,例如只有if沒(méi)有else的分支void func() int a; if (cond1) a = some_value; else if (cond2) a = another_vaule; func2(a);優(yōu)化邏輯,少用分支結(jié)構(gòu),過(guò)多的分支暗示設(shè)計(jì)上可能存在問(wèn)題switch-case分支結(jié)構(gòu)整理case的順序:重要的分支排在前面,相關(guān)的分支排在一起,

19、選擇合適的位置增加分支,不要總是從尾部增加case每個(gè)case的執(zhí)行語(yǔ)句要簡(jiǎn)單,最好只有一行代碼default不是可有可無(wú),要慎重考慮default分支的邏輯能用switch-case就不要用if-else if 鏈,如果預(yù)計(jì)分支持續(xù)增長(zhǎng),應(yīng)先搭好switch-case結(jié)構(gòu),而不是先用if-else,等分支變長(zhǎng)后再改為swith-casebool func(int condition) bool ret = true; switch (condition) case A: func_A(); break; case B: func_B(); break; case C: func_C(); b

20、reak; default: ASSERT(false); /TODO: 增加新的分支 ret = false; 用查找表簡(jiǎn)化分支可將復(fù)雜的分支邏輯變成簡(jiǎn)單的循環(huán)邏輯能很好的適應(yīng)數(shù)據(jù)的變化循環(huán)結(jié)構(gòu)選擇最合適的循環(huán)結(jié)構(gòu):for ( ; ; )while ()do while ();把初始化循環(huán)的代碼緊放在循環(huán)前頭,盡量在循環(huán)體的頭或尾修改隨循環(huán)遞增或遞減的變量void left_shift(int* p_buf, int buf_size) for (int i = 0; i buf_size; i+) p_bufi = p_bufi + 1; 時(shí)刻警惕邊界值的處理,特別是以循環(huán)變量為偏移量讀寫

21、內(nèi)存的情況循環(huán)處理任務(wù)單一化,減少循環(huán)體的代碼行數(shù),方便閱讀和調(diào)試循環(huán)體內(nèi)盡可能少用分支,可放在循環(huán)外的分支盡量不放在循環(huán)內(nèi)void func() for (int i = 0; i N; i+) if (condition) /do job A else /do job B void func() if (condition) for (int i = 0; i N; i+) /do job A else for (int i = 0; i N; i+) /do job B 以優(yōu)雅的方式中斷循環(huán)void func() for (int i = 0; i N; i+) for (int j =

22、 0; j S; j+) for (int k = 0; k M; k+) . if (some condition) i = N; j = S; k = M; 使用循環(huán)要考慮效率因素void reverse(BYTE* buf, int w, int h) for (int y = 0; y w; y+) for (int x = 0; x h; x+) bufy * w + x = 255 - bufy * w + x; void reverse(BYTE* buf, int w, int h) BYTE* p_cur = buf; BYTE* p_end = buf + w * h; w

23、hile (p_cur p_end) *p_cur = 255 - (*p_cur); p_cur+; goto語(yǔ)句能不能用?void func int* p1 = 0; int* p2 = 0; int* p3 = 0; p1 = new intBUF_SIZE1; if (0 = p1) goto error_clean; . p2 = new intBUF_SIZE2; if (0 = p2) goto error_clean; . p3 = new intBUF_SIZE3; if (0 = p3) goto error_clean; .error_clean: if (0 != p1) delete p1; if (0 != p2) delete p2; if (0 != p3) delete p3;如果函數(shù)有返回值,建議聲明并初始化返回值變量,使得代碼簡(jiǎn)潔流暢,過(guò)程清晰,避免出現(xiàn)多路徑返回的情況返回值的初始化與返回力求每個(gè)函數(shù)只有一個(gè)返回點(diǎn),且在函數(shù)的最后返回中途返回的危害:邏輯混亂,代碼可閱讀和可維護(hù)性差,容易導(dǎo)致資源泄漏如果返回動(dòng)態(tài)分配的資源,要明確讓函數(shù)調(diào)用者維護(hù)該資源的生命周期函數(shù)的視覺(jué)效果控制每個(gè)函數(shù)的代碼在50行以內(nèi),

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論