亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C 編程最佳實踐

2019-11-17 05:38:51
字體:
來源:轉載
供稿:網友

C 編程最佳實踐
原文地址:[url]http://www-900.ibm.com/developerWorks/cn/linux/l-bppc/index.sHtml[/url]
[size=18:db26774567][b:db26774567]簡介
風格與指南
其它
結束語
參考資料[/b:db26774567][/size:db26774567]
Shiv Dutta(sdutta@us.ibm.com ),技術顧問,IBM
Gary Hook(ghook@us.ibm.com),高級技術顧問,IBM

2003 年 9 月
盡管 C 語言問世已近 30 年,但它的魅力仍未減退。C 語言繼續吸引著眾多的人們,他們為了編寫新的應用程序,或者移植或維護現有的應用程序而必須學習新技能。
[size=18:db26774567][b:db26774567]簡介[/b:db26774567][/size:db26774567]
本文是為了滿足開發人員的需要而寫的。我們總結了一套指南,無論作為開發人員還是顧問,這些指南多年來一直都很好地指導著我們,我們把它們作為建議提供給您,希望對您的工作有所幫助。您也許不贊同其中的某些指南,但我們希望您會喜歡其中的一些并在您的編程或移植項目中使用它們。
[size=18:db26774567][b:db26774567]風格與指南[/b:db26774567][/size:db26774567]
•使用一種使代碼具有可讀性和一致性的源代碼風格。假如沒有團隊代碼風格或自己的風格,您可以使用與大多數 C 程序員采用的 Kernighan 和 Ritchie 風格相似的風格。然而,舉一個極端的例子,有可能最終會寫出與下面相似的代碼:

[code:1:db26774567]int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell/
o, world!/n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);[/code:1:db26774567]
•— 1984 年模糊 C 代碼大賽“差勁獎”。應代碼作者要求匿名。
•通常將主例程定義為 main()。對應的 ANSI 編寫方式是 int main(void)(假如不考慮命令行參數的話)或 int main( int argc, char **argv 。ANSI 以前的編譯器會省略 void 聲明,或列出變量名以及緊隨其后的聲明。
•空格
充分利用水平和垂直空格??s進和空格間距應反映出代碼的塊結構。
應將條件運算符的長字符串分割成單獨的幾行。例如:

[code:1:db26774567]if (foo->next==NULL && number < limit && limit <=SIZE
&& node_active(this_input)) {...[/code:1:db26774567]
最好改成:

[code:1:db26774567]if (foo->next == NULL
&& number < limit && limit <= SIZE
&& node_active(this_input))
{
...[/code:1:db26774567]同樣,應將描述得很具體的 for 循環分割成不同的行:

[code:1:db26774567]for (curr = *varp, trail = varp;
curr != NULL;
trail = &(curr->next), curr = curr->next )
{
...[/code:1:db26774567]對于其它復雜表達式(如使用三元運算符 ?: 的表達式),最好也將其分割成數行。

[code:1:db26774567] z = (x == y)
? n + f(x)
: f(y) - n;[/code:1:db26774567]

•注釋
注釋應描述正在發生什么事、如何完成它、參數表示什么、使用了哪些全局變量以及任何限制或錯誤。但要避免不必要的注釋。假如代碼比較清楚,并且使用了良好的變量名,那么它應該能夠較好地說明自身。因為編譯器不檢查注釋,所以不保證它們是正確的。與代碼不一致的注釋會起到相反的作用。過多的注釋會使代碼混亂。
下面是一種多余的注釋風格:

[code:1:db26774567] i=i+1; /* Add one to i */[/code:1:db26774567]
很明顯變量 i 遞增了 1。還有更糟的注釋方法:


[code:1:db26774567]/************************************
* *
* Add one to i *
* *

************************************/

i=i+1;[/code:1:db26774567]
•命名約定
具有前導和尾隨下劃線的名稱是為系統用途而保留的,不應當用于任何用戶創建的名稱。約定規定:
1. #define 常量應全部大寫。
2. enum 常量應以大寫字母開頭或全部大寫。
3. 函數、類型定義(typedef)和變量名以及結構(strUCt)、聯合(union)和枚舉(enum)標記名稱應小寫。
為清楚起見,避免使用僅在大小寫上有區別的名稱,如 foo 和 Foo。同樣,避免使用 Foobar 和 foo_bar 這樣的名稱。避免使用看上去相似的名稱。在許多終端和打印機上,“l”、“1”和“I”看上去非常相似。使用名為“l”的變量非常不明智,因為它看上去非常象常量“1”。
•變量名
選擇變量名時,長度不重要,但清楚的表達很重要。長名稱可用于全局變量,因為它不常用,而將在每行循環上要使用的數組下標命名為 i 就完全夠了。假如使用“index”或“elementnumber”的話,不僅輸入得更多,而且會使計算的細節不明確。假如使用長變量名,有時候會使代碼更難理解。比較:


[code:1:db26774567] for(i=0 to 100)
array[i]=0[/code:1:db26774567]

[code:1:db26774567] for(elementnumber=0 to 100)
array[elementnumber]=0;[/code:1:db26774567]
•函數名
函數名應反映函數執行什么操作以及返回什么內容。函數在表達式中使用,通常用于 if 子句,因此它們的意圖應一目了然。例如:
[code:1:db26774567] if (checksize(x))[/code:1:db26774567]
沒有幫助作用,因為它沒有告訴我們 checksize 是在出錯時返回 true 還是在不出錯時返回 true;而
[code:1:db26774567] if (validsize(x))[/code:1:db26774567]
則使函數的意圖很明確。
•聲明
所有的外部數據聲明前都應加上 extern 要害字。
“指針”限定符“*”應緊鄰變量名而不是類型。例如,應使用


[code:1:db26774567] char *s, *t, *u;[/code:1:db26774567]
而不是


[code:1:db26774567] char* s, t, u;[/code:1:db26774567]
后一條語句沒有錯,但可能不是我們期望的,因為沒有將“t”和“u”聲明為指針。
•頭文件
頭文件應按功能組織在一起,即,對單獨子系統的聲明應在單獨的頭文件中。此外,當代碼從一個平臺移植到另一個平臺時有可能發生更改的聲明應位于單獨的頭文件中。
避免使用與庫頭文件名相同的專用頭文件名。語句 #include "math.h" 假如在當前目錄中找不到所期望文件的話,會包括標準庫 math 頭文件。假如這是您期望的結果,可以注釋掉這行 include 語句。
最后說明一點,對頭文件使用絕對路徑名不是一個好主意。C 編譯器的“include-path”選項(在許多系統上為 -I — 大寫的 i)是處理眾多專用頭文件庫的首選方法;它答應在不改變源文件的情況下重新組織目錄結構。
•scanf
在重要的應用程序中永遠不要使用 scanf。它的錯誤檢測不夠完善。請看下面的示例:


[code:1:db26774567] #include <stdio.h>

int main(void)
{
int i;
float f;

scanf("%d %f", &i, &f);

printf("I read %d and %f/n", i, f);
return 0;
}[/code:1:db26774567]
測試運行
Enter an integer and a float: 182 52.38
I read 182 and 52.380001
另一個測試運行
Enter an integer and a float: 6713247896 4.4
I read -1876686696 and 4.400000
•++ 和 --
當對語句中的變量使用遞增或遞減運算符時,該變量不應在語句中出現一次以上,因為求值的順序取決于編譯器。編寫代碼時不要對順序作假設,也不要編寫在某一機器上能夠如期運作但沒有明確定義的行為的代碼:

[code:1:db26774567] int i = 0, a[5];

a[i] = i++; /* assign to a[0]? or a[1]? */[/code:1:db26774567]
•不要被表面現象迷惑
請看以下示例:



[code:1:db26774567] while (c == '/t' c = ' ' c == '/n')
c = getc(f);[/code:1:db26774567]
乍一看,while 子句中的語句似乎是有效的 C 代碼。但是,使用賦值運算符而不是比較運算符卻產生了語義上不正確的代碼。= 的優先級在所有運算符中是最低的,因此將以下列方式解釋該語句(為清楚起見添加了括號):

[code:1:db26774567] while ((c == '/t' c) = (' ' c == '/n'))
c = getc(f);[/code:1:db26774567]
賦值運算符左邊的子句是:

[code:1:db26774567] (c == '/t' c)[/code:1:db26774567]
它不會產生左值。假如 c 包含制表符,則結果是“true”,并且不會執行進一步的求值,而“true”不能位于賦值表達式的左邊。
•意圖要明確。
當您編寫的代碼可以解釋成另一種意圖時,使用括號或用其它方法以確保您的意圖清楚。假如您以后必須處理該程序的話,這有助于您理解您當初的意圖。假如其他人要維護該代碼,這可以讓維護任務變得更簡單。
用能預見可能出現錯誤的方式編碼,有時是可行的。例如,可以將常量放在比較等式的左邊。即,不編寫:

[code:1:db26774567] while (c == '/t' c == ' ' c == '/n')
c = getc(f);[/code:1:db26774567]
而是編寫:

[code:1:db26774567] while ('/t' == c ' ' == c '/n' == c)
c = getc(f);[/code:1:db26774567]
用以下方法卻會得到編譯器診斷:

[code:1:db26774567] while ('/t' = c ' ' == c '/n' == c)
c = getc(f);[/code:1:db26774567]
這種風格讓編譯器發現問題;上面的語句是無效的,因為它試圖對“/t”賦值。
•意想不到的麻煩。
各種 C 實現通常在某些方面各有不同。堅持使用語言中可能對所有實現都是公共的部分會有幫助。通過這樣做,您更輕易將程序移植到新的機器或編譯器,并且不大會碰到編譯器非凡性所帶來的問題。例如,考慮字符串:

[code:1:db26774567] /*/*/2*/**/1[/code:1:db26774567]
這里利用了“最大適合(maximal munch)”規則。假如可以嵌套注釋,則可將該字符串解釋為:
[code:1:db26774567] /* /* /2 */ * */ 1[/code:1:db26774567]
兩個 /* 符號與兩個 */ 符號匹配,因此該字符串的值為 1。假如注釋不嵌套,那么在有些系統上,注釋中的 /* 就被忽略。在另一些系統上會針對 /* 發出警告。無論哪種情況,該表達式可解釋為:

[code:1:db26774567] /* / */ 2 * /* */ 1[/code:1:db26774567]
2 * 1 求值得 2。
•清空輸出緩沖區
當應用程序異常終止時,其輸出的尾部經常會丟失。應用程序可能沒有機會完全清空它的輸出緩沖區。輸出的某一部分可能仍在內存中,并且永遠不會被寫出。在有些系統上,這一輸出可能有幾頁長。
以這種方式丟失輸出會使人誤解,因為它給人的印象是程序在它實際失敗很久之前就失敗了。解決這一問題的方法是強制將輸出從緩沖區清除,非凡是在調試期間。確切的方法隨系統的不同而有所不同,不過也有常用的方法,如下所示:

[code:1:db26774567] setbuf(stdout, (char *) 0);[/code:1:db26774567]
必須在將任何內容寫到標準輸出之前執行該語句。理想情況下,這將是主程序中的第一條語句。
•getchar() — 宏還是函數
以下程序將其輸入復制到其輸出:


[code:1:db26774567] #include <stdio.h>

int main(void)
{
register int a;

while ((a = getchar()) != EOF)
putchar(a);
}[/code:1:db26774567]
從該程序除去 #include 語句將使該程序無法編譯,因為 EOF 將是未定義的。
我們可以用以下方法重新編寫該程序:


[code:1:db26774567] #define EOF -1

int main(void)
{
register int a;

while ((a = getchar()) != EOF)
putchar(a);
}[/code:1:db26774567]
這在許多系統上都可行,但在有些系統上運行要慢很多。
因為函數調用通常要花較長時間,所以經常把 getchar 實現為宏。這個宏定義在 stdio.h 中,所以當除去 #include <stdio.h> 時,編譯器就不知道 getchar 是什么。在有些系統上,假設 getchar 是返回一個 int 的函數。
實際上,許多 C 實現在其庫中都有 getchar 函數,部分原因是為了防止這樣的失誤。于是,在 #include < stdio.h> 遺漏的情況下,編譯器使用 getchar 的函數版本。函數調用的開銷使程序變慢。putchar 有同樣的問題。
•空指針
空指針不指向任何對象。因此,為了賦值和比較以外的目的而使用空指針都是非法的。
不要重新定義 NULL 符號。NULL 符號應始終是常量值零。任何給定類型的空指針總是等于常量零,而與值為零的變量或與某一非零常量的比較,其行為由實現定義。

反引用 null 指針可能會導致希奇的事情發生。
•a+++++b 表示什么?
解析它的唯一有意義的方法是:

[code:1:db26774567] a ++ + ++ b[/code:1:db26774567]
然而,“最大適合”規則要求將它分解為:

[code:1:db26774567] a ++ ++ + b[/code:1:db26774567]
這在語法上是無效的:它等于:

[code:1:db26774567] ((a++)++) + b[/code:1:db26774567]
但 a++ 的結果不是左值,因此作為 ++ 的操作數是不可接受的。于是,解析詞法不明確性的規則使得以語法上有意義的方式解析該示例變得不可能。當然,謹慎的辦法實際上是在不能完全確定它們的意義的情況下,避免這樣的構造。當然,添加空格有助于編譯器理解語句的意圖,但(從代碼維護的角度看)將這一構造分割成多行更可?。?

[code:1:db26774567] ++b;
(a++) + b;[/code:1:db26774567]
•小心處理函數
函數是 C 中最常用的結構概念。它們應用于實現“自頂向下的”問題解決方法 — 即,將問題分解成越來越小的子問題,直到每個子問題都能夠用代碼表示。這對程序的模塊化和文檔記錄有幫助。此外,由許多小函數組成的程序更易于調試。
假如有一些函數參數還不是期望的類型,則將它們強制轉換為期望的類型,即使您確信沒有必要也應該這樣做,因為(假如不轉換的話)它們可能在您最意料不到的時候給您帶來麻煩。換句話說,編譯器通常將函數參數的類型提升和轉換成期望的數據類型以符合函數參數的聲明。但是,在代碼中以手工方式這樣做可以清楚地說明程序員的意圖,并且在將代碼移植到其它平臺時能確保有正確的結果。
假如頭文件未能聲明庫函數的返回類型,那就自己聲明它們。用 #ifdef/#endif 語句將您的聲明括起來,以備代碼被移植到另一個平臺。
函數原型應當用來使代碼更健壯,使它運行得更快。
•懸空 else
除非知道自己在做什么,否則應避免“懸空 else”問題:


[code:1:db26774567] if (a == 1)
if (b == 2)
printf("***/n");
else
printf("###/n");[/code:1:db26774567]

規則是 else 附加至最近的 if。當有疑慮時,或有不明確的可能時,添加花括號以說明代碼的塊結構。
•數組界限
檢查所有數組的數組界限,包括字符串,因為在您現在輸入“fubar”的地方,有人可能會輸入“floccinaucinihil
ipilification”。健壯的軟件產品不應使用 gets()。
C 下標以零作為開始的這一事實使所有的計數問題變得更簡單。然而,把握如何處理它們需要花些努力。
•空語句
for 或 while 循環的空語句體應當單獨位于一行并加上注釋,這樣就表明這個空語句體是有意放置的,而不是遺漏了代碼。

[code:1:db26774567] while (*dest++ = *src++)
; /* VOID */[/code:1:db26774567]
•測試真(true)還是假(false)
不要以缺省方式測試非零值,即:

[code:1:db26774567] if (f() != FAIL)[/code:1:db26774567]
優于

[code:1:db26774567] if (f())[/code:1:db26774567]
盡管 FAIL 的值可能是 0(在 C 中視為假(false))。(當然,應當在這一風格與“函數名”一節中演示的構造之間作出權衡。)當以后有人認為失敗的返回值應該是 -1 而不是 0 時,顯式的測試對您會有幫助。
常見的問題是使用 strcmp 函數測試字符串是否相等,決不應該以缺省方式處理它的結果。更可取的方法是定義宏 STREQ:

[code:1:db26774567]#define STREQ(str1, str2) (strcmp((str1), (str2)) == 0)[/code:1:db26774567]
用這種方法,語句

[code:1:db26774567] If ( STREQ( inputstring, somestring ) ) ...[/code:1:db26774567]
就具有隱含的行為,該行為不大會在您不知情的情況下改變(人們往往不會重新編寫或重新定義象 strcmp() 這樣的標準庫函數)。
不要用 1 檢查相等性的布爾值(TRUE 和 YES 等);而要用 0 測試不等性(FALSE 和 NO 等)。絕大多數函數被確保在條件為假(false)時返回 0,但僅在條件為真(true)時才返回非零。因此,最好將

[code:1:db26774567] if (func() == TRUE) {...[/code:1:db26774567]
寫成

[code:1:db26774567] if (func() != FALSE)[/code:1:db26774567]
•嵌入語句
使用嵌入賦值語句要看時間和地點。在有些構造中,假如不使用更多且不易閱讀的代碼就沒有更好的方法來實現結果:

[code:1:db26774567] while ((c = getchar()) != EOF) {
process the character
}[/code:1:db26774567]
使用嵌入賦值語句來提高運行時性能是可能的。但是,您應當在提高速度和降低可維護性之間加以權衡,在人為指定的位置使用嵌入賦值語句會導致可維護性降低。例如:


[code:1:db26774567] x = y + z;
d = x + r;[/code:1:db26774567]
不應被替換為:

[code:1:db26774567] d = (x = y + z) + r;[/code:1:db26774567]
即使后者可能節省一個周期也不行。最終,這兩者之間在運行時間上的差異將隨著優化器的增強而減少,易維護性的差異卻將增加。
•goto 語句
應保守地使用 goto。從數層 switch、for 和 while 嵌套中跳出來時,使用該語句很有效,不過,假如有這樣的需要,則表明應將內部構造分解成單獨的函數。

[code:1:db26774567] for (...) {
while (...) {
...
if (wrong)
goto error;

}
}
...
error:
print a message[/code:1:db26774567]
當必須使用 goto 時,隨附的標號應單獨位于一行,并且同后續代碼的左邊相距一個制表符或位于一行的開頭。對 goto 語句和目標都應加上注釋,說明其作用和目的。
•switch 中的“落空”(fall-through)
當一塊代碼有數個標號時,將這些標號放在單獨的行。這種風格與垂直空格的使用一致,并且使重新安排 case 選項(假如那是必需的話)成了一項簡單的任務。應對 C switch 語句的“落空”特征加以注釋,以便于以后的維護。假如這一特性曾給您帶來“麻煩”,那么您就能夠理解這樣做的重要性!

[code:1:db26774567] switch (eXPr) {
case ABC:
case DEF:
statement;
break;
case UVW:
statement; /*FALLTHROUGH*/
case XYZ:
statement;
break;
}[/code:1:db26774567]
盡管從技術上說,最后一個 break 不是必需的,但是,假如以后要在最后一個 case 之后添加了另一個 case,那么一致地使用 break 可以防止“落空”錯誤。假如使用 default case 語句的話, 它應當永遠是最后一個,并且(假如它是最后的語句)不需要最后的 break 語句。
•常量
符號常量使代碼更易于閱讀。應盡量避免使用數字常量;使用 C 預處理器的 #define 函數給常量賦予一個有意義的名稱。在一個位置(最好在頭文件中)定義值還會使得治理大型程序變得更輕易,因為只需更改定義就可以統一地更改常量值??梢钥紤]使用枚舉數據類型作為對聲明只取一組離散值的變量的改進方法。使用枚舉還可以讓編譯器對您枚舉類型的任何誤用發出警告。任何直接編碼的數字常量必須至少有一個說明值的出處的注釋。
常量的定義與它的使用應該一致;例如,將 540.0 用于浮點數,而不要通過隱式浮點類型強制轉換使用 540。也就是說,在有些情況下,常量 0 和 1 可以以本身的形式直接出現,而不要以定義的形式出現。例如,假如某個 for 循環遍歷一個數組,那么:

[code:1:db26774567] for (i = 0; i < arraysub; i++)[/code:1:db26774567]
非常合理,而代碼:

[code:1:db26774567] gate_t *front_gate = opens(gate[i], 7);
if (front_gate == 0)
error("can't open %s/n", gate[i]);[/code:1:db26774567]
就不合理。在第二個示例中,front_gate 是指針;當值是指針時,它應與 NULL 比較而不與 0 比較。即使象 1 或 0 這樣的簡單值,通常最好也使用象 TRUE 和 FALSE 這樣的定義來表示(有時 YES 和 NO 讀起來更清楚)。
不要在需要離散值的地方使用浮點變量。這是由于浮點數不精確的表示決定的(請參閱以上 scanf 中的第二個測試)。使用 <= 或 >= 測試浮點數;精確比較(== 或 !=)也許不能檢測出“可接受的”等同性。
應將簡單的字符常量定義為字符文字而不是數字。不提倡使用非文本字符,因為它們是不可移植的。假如必須使用非文本字符,尤其是在字符串中使用它們,則應使用三位八進制數(不是一個字符)的轉義字符(例如“/007”)來編寫它們。即便如此,這樣的用法應視為與機器相關,并且應按這一情況來處理。
•條件編譯
條件編譯可用于機器相關性、調試以及在編譯時設置某些選項??梢杂脽o法預料的方式輕易地組合各種控制。假如將 #ifdef 用于機器相關性,應確保當沒有指定機器時會出錯,而不是使用缺省的機器。#error 偽指令可以較方便地用于這一用途。假如使用 #ifdef 進行優化,缺省值應是未優化的代碼而不是不可編譯或不正確的程序。要確保對未優化的代碼進行了測試。
[size=18:db26774567][b:db26774567]其它[/b:db26774567][/size:db26774567]
•象 Make 這樣用于編譯和鏈接的實用程序極大簡化了將應用程序從一個環境移到另一個環境的任務。在開發期間,make 僅對那些自上次使用 make 以來發生了更改的模塊進行重新編譯。
經常使用 lint。lint 是 C 程序檢查器,它檢查 C 源文件以檢測并報告函數定義和調用之間類型的不匹配和不一致,以及可能存在的程序錯誤等。
此外,研究一下編譯器文檔,了解那些使編譯器變得“吹毛求疵”的開關。編譯器的工作是力求精確,因此通過使用適當的命令行選項讓它報告可能存在的錯誤。

•使應用程序中全局符號的數量最少。這樣做的好處之一是與系統定義的函數沖突的可能性降低。
•許多程序在遺漏輸入時會失敗。對所有的程序都應進行空輸入測試。這也可能幫助您理解程序的工作原理。
•不要對您的用戶或您所用的語言實現有任何過多的假設。那些“不可能發生”的事情有時的確會發生。健壯的程序可以防范這樣的情形。假如需要找到某個邊界條件,您的用戶將以某種方式找到它!
永遠不要對給定類型的大小作任何假設,尤其是指針。
當在表達式中使用 char 類型時,大多數實現將它們當作無符號類型,但有些實現把它們作為有符號的類型。當在算術表達式使用它們時,建議始終對它們進行類型強制轉換。
不要依靠對自動變量和 malloc 返回的內存進行的初始化。
•使您程序的目的和結構清楚。
•要記住,可能會在以后要求您或別的人修改您的代碼或在別的機器上運行它。細心編寫您的代碼,以便能夠將它移植到其它機器。
[size=18:db26774567][b:db26774567]結束語[/b:db26774567][/size:db26774567]
應用程序的維護要花去程序員的大量時間,這是眾所周知的事。部分原因是由于在開發應用程序時,使用了不可移植和非標準的特性,以及不令人滿足的編程風格。在本文中,我們介紹了一些指南,多年來它們一直給予我們很大幫助。我們相信,只要遵守這些指南,將可以使應用程序維護在團隊環境中變得更輕易。
[size=18:db26774567][b:db26774567]參考資料[/b:db26774567][/size:db26774567]
•Obfuscated C and Other Mysteries,由 Don Libes 編寫,John Wiley and Sons, Inc. ISBN 0-471-57805-3
•The C Programming Language,Second Edition,由 Brian W. Kernighan 和 Dennis M. Ritchie 撰寫,Prentice-Hall,ISBN 0-13-110370-9
•Safer C,由 Les Hatton 編寫,McGraw-Hill,ISBN 0-07-707640-0
•C Traps and Pitfalls 由 Andrew Koenig 編寫,AT&T Bell Laboratories,ISBN 0-201-17928-9

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品国偷自产在线视频99| 日韩在线观看精品| 中文字幕亚洲一区二区三区五十路| 精品视频中文字幕| 久久香蕉频线观| 久久免费视频在线| 国产精品久久999| 欧美人在线视频| 亚洲综合在线中文字幕| 亚洲a成v人在线观看| 成人看片人aa| 日韩精品久久久久久久玫瑰园| 国产午夜精品视频免费不卡69堂| 亚洲视频在线免费观看| 欧美精品videos另类日本| 久久久999精品免费| 亚洲18私人小影院| 国产91色在线播放| 亚洲国产成人精品久久久国产成人一区| 欧美日韩国产激情| 日本韩国在线不卡| 欧美日韩国产一区二区三区| 免费91麻豆精品国产自产在线观看| 亚洲片国产一区一级在线观看| 亚洲色图17p| 日本久久久久久久久久久| 国产一区在线播放| 国产精品中文久久久久久久| 精品久久久久久国产| 成人福利视频网| 国产精品a久久久久久| 日韩免费观看av| 欧美一级免费视频| 久久精品免费播放| 精品亚洲一区二区三区| 亚洲大胆美女视频| 午夜精品福利电影| 中文字幕日韩高清| 日本精品视频网站| 亚洲老板91色精品久久| 91精品国产高清自在线看超| 国产ts人妖一区二区三区| 亚洲偷欧美偷国内偷| 欧美午夜激情视频| 欲色天天网综合久久| 欧美夫妻性视频| 日韩中文娱乐网| 欧美精品18videos性欧| 久久久精品在线| 久久中文久久字幕| 97视频com| 中文字幕日韩高清| 国产精品久在线观看| 久久av资源网站| 国产精品国语对白| 国内精品视频一区| 国产欧美久久久久久| 精品久久久久久亚洲国产300| 国产精品99久久99久久久二8| 7777kkkk成人观看| 91精品国产91久久久| 成人欧美一区二区三区在线湿哒哒| 97视频国产在线| 成人黄色片网站| 久久av资源网站| 国产999在线| 精品电影在线观看| 精品一区二区三区三区| 青青久久av北条麻妃黑人| 久久九九亚洲综合| 亚洲欧美精品一区二区| 神马国产精品影院av| 国产一区二区三区免费视频| 国产精品久久久久不卡| 日韩av在线免费观看一区| 日韩成人在线电影网| 欧美猛交免费看| 精品综合久久久久久97| 久久精品99久久香蕉国产色戒| 国产精品白嫩初高中害羞小美女| 日韩中文字幕视频在线| 啪一啪鲁一鲁2019在线视频| 国产不卡精品视男人的天堂| 亚洲人成自拍网站| 日韩av最新在线| 国产精品va在线播放我和闺蜜| 欧美激情免费在线| 91精品国产综合久久久久久蜜臀| 国产深夜精品福利| 亚洲qvod图片区电影| 久久久噜噜噜久噜久久| 亚洲高清福利视频| 不卡中文字幕av| 欧美自拍视频在线观看| 亚洲黄页网在线观看| 亚洲电影免费观看高清完整版| 91精品久久久久| 日韩女优在线播放| 久久天堂电影网| 91精品久久久久久久久| 亚洲专区国产精品| 国产精品久久久久久久久粉嫩av| 国产精品久久久久久久一区探花| 色偷偷噜噜噜亚洲男人的天堂| 疯狂做受xxxx高潮欧美日本| 欧美成年人视频网站| 久久亚洲综合国产精品99麻豆精品福利| 97视频免费看| 一本大道久久加勒比香蕉| 欧美国产日本高清在线| 精品久久久久久久久久久久久| 久久av中文字幕| 精品国产乱码久久久久久虫虫漫画| 在线播放国产一区中文字幕剧情欧美| 亚洲欧美日韩一区二区在线| 欧洲亚洲女同hd| 日韩av中文在线| 人人澡人人澡人人看欧美| 宅男66日本亚洲欧美视频| 亚洲天堂成人在线| 久久综合免费视频影院| 91精品国产高清久久久久久| 国产国语刺激对白av不卡| 欧美亚洲国产精品| 91精品国产综合久久香蕉最新版| 久久综合色影院| 一区二区三区黄色| 欧美老女人性生活| 亚洲国产精品yw在线观看| 亚洲品质视频自拍网| 欧美精品video| 日韩欧美在线观看| 亚洲欧美日韩直播| 一本一道久久a久久精品逆3p| 国产一区二区三区高清在线观看| 亚洲国产成人在线视频| 久久久99免费视频| 亚洲九九九在线观看| 国产精品偷伦视频免费观看国产| 欧美性猛交xxxx偷拍洗澡| 欧美韩日一区二区| 国产97免费视| 国产情人节一区| 国产成人一区二区三区小说| 久久久久久久国产精品视频| 久久久99久久精品女同性| 国产乱肥老妇国产一区二| 久久久噜噜噜久久久| 欧美成人免费小视频| 亚洲人成电影网站色| 久久99亚洲热视| 国产v综合v亚洲欧美久久| 中文字幕久久久| 精品久久久久久中文字幕| 久久久久久国产| 午夜精品www| 国内外成人免费激情在线视频网站| 国产午夜精品一区理论片飘花| 日韩高清中文字幕| 亚洲精品456在线播放狼人| 亚洲少妇激情视频| 欧美夜福利tv在线| 日本中文字幕久久看| 8x拔播拔播x8国产精品|