大型遊戲公司內部的編碼規範(轉載)

大型遊戲公司內部的編碼規範

 (轉載自立仔空間: http://vzzllblog.bokee.com/4718276.html  

說明:這是公司裏數以千計的開發人員必須遵守的規則,不是教條。
自由發揮的編程風格只適用於手工作坊、幾個人的小公司,對於需要數以十計、百計的技術人員協作的項目,更需要工程化的規定。每個人確實是一顆小螺絲了,也許有些殘酷,但是事實就是這樣的。

.排版
1.1
規則:程序塊應採用縮進風格編寫,縮進的空格數爲4個。
說明:對於由開發工具自動生成的代碼可以有不一致。
1.2
規則:相對獨立的程序塊之間、變量說明之後應加空行。
示例:如下例子不符合規範。
if( DD_OK != lpSurface->Flip() )
{
  ... // program code
}
sprite++;
waitTime(30);

應如下書寫
if( DD_OK != lpSurface->Flip() )
{
  ... // program code
}

sprite++;
waitTime(30);
1.3
規則:較長的語句(>80字符)要分成多行書寫。
長表達式要在低優先級操作符處劃分新行,操作符放在新行之首,劃分出的新行要進行適當的縮進,使排版整齊,語句可讀。
示例:
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE
                | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
videoBuffer[x+indexX+(y+indexY)*pitch] = bitmapBufferOffset
+ bitmap[indexX+indexY*bitmapWidth]
1.4
規則:循環、判斷等語句中若有較長的語句,則應進行適應的劃分。
應首先考慮在分號處劃分新行,其次長表達式要在低優先級操作符處劃分新行,操作符放在新行之首。
示例:
if( (NULL != backSurface ))
  && (NULL != primarySurface)))
{
  ... // program code
}

for(i = 0, j = 0; (i < back[pixel].Width) && (j < back[pixel].Height);
i++, j++)
{
  ... // program code
}

for(i = 0, j = 0;
    (i < backBufferWidth) && (j < backBufferHeight);
    i++, j++)
{
  ... // program code
}
1.5
規則:若函數或過程中的參數較長,則應進行適當的劃分。
示例:
createDirectDraw(NULL,(void**) &pDirectDraw,
            IID_IdirectDraw7, NULL);

PDirectDraw->CreatePalette( DDPCAPS_8BIT | DDPCAPS_ALLOW256
| DDPCAPS_INITIALIZE, palette,&pddpal,NULL );
1.6
規則:一行只寫一條語句。
示例:如下例子不符合規範。
rect.length = 0; rect.width = 0;

應如下書寫
rect.length = 0;
rect.width = 0;
1.7
規則:條件判斷語句語句應獨佔一行,且主判斷語句的執行語句部分需加塊符號。
C/C++中的條件語句iffordowhilecaseswitchdefault等都應按此規則排版(其中iffordowhileswitch爲主判斷語句)。
示例:如下例子不符合規範。
if(NULL == backBuffer) return;

應如下書寫:
if(NULL == backBuffer)
{
  return;
}
1.8
推薦:對齊只使用TAB鍵,不使用空格鍵。
說明:目前絕大多數編輯器都支持TAB鍵長度調整,此時應將TAB鍵長度設置爲4;而空格鍵操作較爲繁瑣,而且在使用鍵盤時有所不便,應儘量避免使用空格鍵來進行對齊操作。
1.9
規則:程序塊中的代碼應採用縮進風格。
這裏的程序塊包括函數、過程、方法、數據結構定義、循環體、判斷體、case語句體等。
示例:如下例子不符合規範。
void exampleFun( int errCOde )
{
for (...)
{
loop ++;
  ... // program code
}


int first = 0;
switch( errCode )
{
case DDERR_SURFACELOST:
drawSurface->restore();
break;
case ...
}
  ... // program code
}

應如下書寫。
void exampleFun( int errCOde )
{
for (...)
{
loop ++;
  ... // program code
}

int first = 0;

switch( errCode )
{
case DDERR_SURFACELOST:
drawSurface->restore();
break;
case ...
}

  ... // program code
}
1.10
規則:程序塊的分界符應各獨佔一行並與引用它們的語句左對齊。
在函數體的開始、類的定義、結構的定義、枚舉的定義以及iffordowhileswitchcase語句中的程序都要採用如上的縮進方式。
示例:如下例子不符合規範。
for(...) {
  ... // program code
}

if(...)
  {
  ... // program code
  }

void exampleFun( void )
  {
  ... // program code
  }

應如下書寫。
for(...)
{
  ... // program code
}

if(...)
{
  ... // program code
}

void exampleFun( void )
{
  ... // program code
}
1.11
規則:說明性文件中對來自不同源代碼文件中的說明應分塊進行。
1.12
規則:進行相關賦值或者初始化時,應進行字段對齊。
如對關係較爲緊密的結構成員、數組、宏進行定義初始化時,要進行字段對齊。
示例:
struct BufferManager msgBuf[]=
{
{ LockSize, 54, NULL, 0, 0, 0 },
{ LockSize, 280,   NULL
0, 0, 0 },
{ LockSize, 10,   NULL, 0, 0, 0 },
{ LockSize, 10, NULL, 0, 0, 0 }
};

rect.top = 0;
rect.left = 0;
rect.right = 300;
rect.bottom = 200;

#define MaxScrnWidth 640
#define MaxScrnHeight 480
1.13
推薦:在語句中間添加適量空格,以使得代碼更清晰。
在兩個以上的關鍵字、變量、常量進行對等操作時,操作符前後要加空格;進行非對等操作時,如果是關係密切的操作符(如類中的.->),後不應加空格。採用這種鬆散方式編寫代碼的目的是使代碼更加清晰。
由於留空格所產生的清晰性是相對的,所以,在已經非常清晰的語句中沒有必要再留空格,如果語句已足夠清晰則括號內側(即左括號後面和右括號前面)不需要加空格,多重括號間可以不加空格,因爲在C/C++語言中括號已經是最清晰的標誌了。
在長語句中,如果需要加的空格非常多,那麼應該保持整體清晰,而在局部不加空格。給操作符留空格時不要連續留兩個以上空格。

示例:
(1)
逗號、分號只在後面加空格。
int a, b, c;

(2)
比較操作符, 賦值操作符"=" "+=",算術操作符"+""%",邏輯操作符"&&""&",位域操作符"<<""^"等雙目操作符的前後加空格。
if (timeTicks >= MaxTicks)
{
timeTicks = 0;
  ... // program code
}

(3)"!"
"~""++""--""&"(地址運算符)等單目操作符前後不加空格。
*p = 'a';       //
內容操作"*"與內容之間
flag = !isEmpty; //
非操作"!"與內容之間
p = &mem;       //
地址操作"&" 與內容之間
i++;         // "++","--"
與內容之間

(4)"->"
"."前後不加空格。
lpDraw->id = pid; // "->"
指針前後不加空格

(5) if
forwhileswitch等與後面的括號間可以加空格,使if等關鍵字更爲突出、明顯;也可以不加空格,使得if等關鍵字與條件聯繫更緊密。無論如何,開發人員只應選擇其中一種形式,並在同一產品開發中保持一致的風格。
if ( a>=b && c>d )
或者
if( a>=b && c>d )

(6)
ifforwhileswitch等語句,如爲多條件組合形式,條件內部可以不加空格,以使各條件更明確。
if ( lines>=height && chars>width && size>maxSize )
1.14
推薦:一行程序以小於80字符爲宜,不要寫得過長。
考慮在大多數情況下一行程序在屏幕顯示時的可見性,一行程序不宜過長,目前建議不大於80個字符。
.註釋
2.1
推薦:一般情況下,源程序有效註釋量應在20%~40%之間。
註釋的原則是有助於對程序的閱讀理解。
對於重點函數/方法的解釋,和函數/方法中關鍵算法、複雜操作或者與特定內容相關的程序部分,以及看來顯然不合理的(但是實際上是合理的)程序部分,應給出清楚、簡潔的註釋。
如果本身已經比較清楚的程序部分,不宜再進行註釋。過多的註釋反而會降低程序的可讀性。
本規則推薦在源程序的註釋量,並非強制要求。然而在通常情況下,大多數源程序的有效註釋量應在此範圍內。
2.2
規則:說明性文件頭部應進行註釋。
說明性文件(如頭文件.h文件、.inc文件、.def文件、編譯說明文件.cfg等)的註釋應列出:版權說明、版本號、生成日期、作者、內容、功能、與其它文件的關係、修改日誌等,頭文件的註釋中還應有函數功能簡要說明。
示例:下面這段頭文件的頭註釋比較標準,當然,並不侷限於此格式,但上述信息建議要包含在內。
/*************************************************
Copyright (C), 1988.1999, XXXX Tech. Co., Ltd.
File name:     //
文件名
Author:    
Version:    
Date: //
作者、版本及完成日期
Description:   //
用於詳細說明此程序文件完成的主要功能,與其他模塊
            //
或函數的接口,輸出值、取值範圍、含義及參數間的控
            //
制、順序、獨立或依賴等關係
Others:       //
其它內容的說明
Function List:   //
主要函數列表,每條記錄應包括函數名及功能簡要說明
  1. ....
History:       //
修改歷史記錄列表,每條修改記錄應包括修改日期、修改者及修改內容簡述
  1. Date:
    Author:
    Modification:
  2. ...
*************************************************/
2.3
規則:源文件頭部應進行註釋。
源文件頭部應列出:版權說明、版本號、生成日期、作者、模塊目的/功能、主要函數及其功能、修改日誌等。
示例:下面這段源文件的頭註釋比較標準,當然,並不侷限於此格式,但上述信息建議要包含在內。
/************************************************************
Copyright (C), 1988.1999, XXXX Tech. Co., Ltd.
FileName: test.cpp
Author:     Version :       Date:
Description:   //
模塊描述    
Version:       //
版本信息
Function List:   //
主要函數及其功能
  1. -------
History:       //
歷史修改記錄
       
    David   96/10/12   1.0   build this moudle
***********************************************************/
說明:Description一項描述本文件的內容、功能、內部各部分之間的關係及本文件與其它文件關係等。History是修改歷史記錄列表,每條修改記錄應包括修改日期、修改者及修改內容簡述。
2.4
規則:函數頭部應進行註釋。
函數註釋要列出:函數的目的/功能、輸入參數、輸出參數、返回值、調用關係(函數、表)等。
對於簡單、自說明的函數可以不做出全面的註釋。
示例:下面這段函數的註釋比較標準,當然,並不侷限於此格式,但上述信息建議要包含在內。
/*************************************************
Function:     //
函數名稱
Description:   //
函數功能、性能等的描述
Calls:       //
被本函數調用的函數清單
Called By:     //
調用本函數的函數清單
Table Accessed: //
被訪問的表(此項僅對於牽扯到數據庫操作的程序)
Table Updated: //
被修改的表(此項僅對於牽扯到數據庫操作的程序)
Input:       //
輸入參數說明,包括每個參數的作
            //
用、取值說明及參數間關係。
Output:       //
對輸出參數的說明。
Return:       //
函數返回值的說明
Others:       //
其它說明
*************************************************/
2.5
推薦:邊寫代碼邊寫註釋。
修改代碼的同時修改相應的註釋,以保證註釋與代碼的一致性。不再有用的註釋要刪除。
2.6
規則:註釋的內容應清楚、明瞭,含義準確,防止註釋二義性。
錯誤的註釋不但無益反而有害。
2.7
規則:避免在註釋中使用縮寫,特別是非常用縮寫。
如確需使用縮寫,在使用縮寫之前,應對縮寫進行必要的說明;標準的縮寫(如國家標準、行業標準、企業標準),可以在註釋中使用,此時仍然建議對縮寫進行必要的說明。
2.8
規則:註釋應與其描述的代碼緊鄰。
對代碼的註釋應放在其緊上方或右方(對單條語句的註釋)相鄰位置,不可放在下面,如放於緊上方則需與其上面的代碼用空行隔開。如放於右方且有多條註釋相鄰,各註釋應對齊。
示例:如下例子不符合規範。
/*
初始化鼠標輸入設備,並設置爲相對座標方式 */

LPDIRECTINPUT8 pDi;//DX
輸入
IDIRECTINPUTDEVICE8 mouse;//
鼠標輸入設備
initDirectDraw();
pDi->CreateDevice(GUID_SysMouse, &mouse, NULL);
mouse->SetCooperativeLevel(mainWndHwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
mouse->SetDataFormat(&c_dfDIMouse);
mouse->Acquire();
initKeyboard();

應如下書寫
initDirectDraw();

LPDIRECTINPUT8 pDi; //DX
輸入
IDIRECTINPUTDEVICE8 mouse; //
鼠標輸入設備

/*
初始化鼠標輸入設備,並設置爲相對座標方式 */
pDi->CreateDevice(GUID_SysMouse, &mouse, NULL);
mouse->SetCooperativeLevel(mainWndHwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
mouse->SetDataFormat(&c_dfDIMouse);
mouse->Acquire();

initKeyboard();
2.9
規則:對於特定含義的標識符,如其命名不是充分自說明的,聲明時應加以註釋。
變量、常量、宏的註釋應放在其緊上方相鄰位置或右方。
示例:
/*
精靈總數 */
#define MaxSprite 1000

#define MaxSurface 1000 /* Ddraw
表面總數 */
2.10
規則:數據結構聲明,如其命名不是充分自說明的,聲明時應加以註釋。
對數據結構的註釋應放在其上方相鄰位置,不可放在下面;對結構中的每個域的註釋放在此域的右方。
示例:可按如下形式說明枚舉/數據/聯合結構。
/*
16色下顏色代碼 */
enum COLOR
{
  BLACK, /*
黑色 */
RED,   /*
紅色 */
...
  WHITE, /*
白色*/
};
2.11
規則:全局變量應有較詳細的註釋。
包括對其功能、取值範圍、哪些函數或過程存取它以及存取時注意事項等的說明。
示例:
/*
當函數失敗時返回錯誤碼,保存在全局變量errCode */ // 變量作用、含義
/* errCode
爲不等於0的任意長整數;具體數值由開發工具確定*/   // 變量取值範圍
/* errCode
僅供errman.cpp調用 */   // 使用方法
LONG errCode;
2.12
規則:註釋與所描述內容應進行同樣的縮排。
說明:可使程序排版整齊,並方便註釋的閱讀與理解。
示例:如下例子,排版不整齊,閱讀稍感不方便。
void fun( void )
{
/* code one comments */
  CodeBlock One

    /* code two comments */
  CodeBlock Two
}

應改爲如下佈局。
void fun( void )
{
  /* code one comments */
  CodeBlock One

  /* code two comments */
  CodeBlock Two
}
2.13
推薦:對重要變量的定義和分支語句(條件分支、循環語句等)應編寫註釋。
說明:這些語句往往是程序實現某一特定功能的關鍵,對於維護人員來說,良好的註釋幫助更好的理解程序,有時甚至優於看設計文檔。
2.14
規則:不中斷的case語句應加註釋。
對於switch語句下的case語句,如果因爲特殊情況需要處理完一個case後進入下一個case處理,必須在該case語句處理完、下一個case語句前加上明確的註釋。這樣比較清楚程序編寫者的意圖,有效防止無故遺漏break語句。本規則是2.2.1的細化。
示例:
case DIK_DOWN:
  ProcessDown();
  break;
case DIK_RIGHT:
  ProcessRight();
ProcessCFW_B();
//
不要break出去,因爲還要處理向前行走的邏輯
case DIK_END:  
  ProcessEnd();  
  break;
...
2.15
推薦:避免在一行代碼或表達式的中間插入註釋。
說明:除非必要,不應在代碼或表達中間插入註釋,否則容易使代碼可理解性變差。
2.16
推薦:對程序單元應進行正確的命名以及合理組織代碼的結構,使代碼自說明。
說明:清晰準確的函數、過程、結果、變量等的命名,可增加代碼可讀性,並減少不必要的註釋。
2.17
推薦:應在代碼的功能、意圖層次上進行註釋,提供有用、額外的信息。
說明:註釋的目的是解釋代碼的目的、功能和採用的方法,提供代碼以外的信息,幫助讀者理解代碼,防止沒必要的重複註釋信息。本規則是2.2.1的細化。
示例:如下注釋意義不大。
/*
如果receiveFlag設置爲true */
if( receiveFlag )
...
而如下的註釋則給出了額外有用的信息。
/*
如果收到其它精靈的消息 */
if( receiveFlag )
...
2.18
推薦:應在程序塊的結束行右方加註釋標記,以表明某程序塊的結束。
說明:當代碼段較長,特別是多重嵌套時,這樣做可以使代碼更清晰,更便於閱讀。
示例:參見如下例子。
if(...)
{
  // program code

  while(index < MaxSprite)
  {
    // program code
  } /* end of while(index < MaxSprite) */ //
指明該條while語句結束
} /* end of if (...)*/ //
指明是哪條if語句結束
2.19
推薦:註釋應考慮程序易讀及外觀排版的因素。
註釋語言不統一,影響程序易讀性和外觀排版,使用的語言若是中、英兼有的,建議使用中文。

 

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