欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Recommended C Style and Coding Standards中文翻譯版第2/3頁

 更新時(shí)間:2014年04月28日 11:45:23   作者:  
本文翻譯自Recommended C Style and Coding Standards(C語言編碼風(fēng)格和標(biāo)準(zhǔn)),需要的朋友可以參考下

6. 空格

復(fù)制代碼 代碼如下:
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);}

- 不光彩的事情,模糊C代碼大賽,1984年。作者要求匿名。
通常情況下,請使用縱向和橫向的空白。縮進(jìn)和空格應(yīng)該反映代碼的塊結(jié)構(gòu)。例如,在一個(gè)函數(shù)定義與下一個(gè)函數(shù)的注釋之間,至少應(yīng)該有兩行空白。

如果一個(gè)條件分支語句過長,那就應(yīng)該將它拆分成若干單獨(dú)的行。

復(fù)制代碼 代碼如下:

    if (foo->next==NULL && totalcount<needed && needed<=MAX_ALLOT
        && server_active(current_input)) { ...

也許下面這樣更好
復(fù)制代碼 代碼如下:

    if (foo->next == NULL
        && totalcount < needed && needed <= MAX_ALLOT
        && server_active(current_input))
    {
        ...

類似地,復(fù)雜的循環(huán)條件也應(yīng)該被拆分為不同行。
復(fù)制代碼 代碼如下:

    for (curr = *listp, trail = listp;
        curr != NULL;
        trail = &(curr->next), curr = curr->next )
    {
        ...

其他復(fù)雜的表達(dá)式,尤其是那些使用了?:操作符的表達(dá)式,最好也能拆分成多行。
復(fù)制代碼 代碼如下:

    c = (a == b)
        ? d + f(a)
        : f(b) - d;

當(dāng)關(guān)鍵字后面有放在括號內(nèi)的表達(dá)式時(shí),應(yīng)該使用空格將關(guān)鍵字與左括號分隔(sizeof操作符是個(gè)例外)。在參數(shù)列表中,我們也應(yīng)該使用空格顯式 的將各個(gè)參數(shù)隔開。然而,帶有參數(shù)的宏定義一定不能在名字與左括號間插入空格,否則C預(yù)編譯器將無法識別后面的參數(shù)列表。

7. 例子

復(fù)制代碼 代碼如下:
/*
         * Determine if the sky is blue by checking that it isn't night.
         * CAVEAT: Only sometimes right.  May return TRUE when the answer
         * is FALSE.  Consider clouds, eclipses, short days.
         * NOTE: Uses 'hour' from 'hightime.c'.  Returns 'int' for
         * compatibility with the old version.
         */
                int                             /* true or false */
        skyblue()
        {
                extern int      hour;           /* current hour of the day */

                return (hour >= MORNING && hour <= EVENING);
        }

        /*
         * Find the last element in the linked list
         * pointed to by nodep and return a pointer to it.
         * Return NULL if there is no last element.
         */
                node_t *
        tail(nodep)
                node_t  *nodep;                 /* pointer to head of list */
        {
                register node_t *np;            /* advances to NULL */
                register node_t *lp;            /* follows one behind np */

                if (nodep == NULL)
                        return (NULL);
                for (np = lp = nodep; np != NULL; lp = np, np = np->next)
                        ;       /* VOID */
                return (lp);
        }

8. 簡單語句

每行只應(yīng)該有一條語句,除非多條語句關(guān)聯(lián)特別緊密。

復(fù)制代碼 代碼如下:

    case FOO:  oogle (zork);  boogle (zork);  break;
    case BAR:  oogle (bork);  boogle (zork);  break;
    case BAZ:  oogle (gork);  boogle (bork);  break;

for或while循環(huán)語句的空體應(yīng)該單獨(dú)放在一行并加上注釋,這樣可以清晰的看出空體是有意而為,并非遺漏代碼。
復(fù)制代碼 代碼如下:

    while (*dest++ = *src++)
        ;    /* VOID */

不要對非零表達(dá)式進(jìn)行默認(rèn)測試,例如:
復(fù)制代碼 代碼如下:

    if (f() != FAIL)

比下面的代碼更好
復(fù)制代碼 代碼如下:

    if (f())

即使FAIL的值可能為0(在C中0被認(rèn)為是假)。當(dāng)后續(xù)有人決定使用-1替代0作為失敗返回值時(shí),一個(gè)顯式的測試將解決你的問題。即使比較的值永遠(yuǎn)不會(huì)改變,我們也應(yīng)該使用顯式的比較;例如
復(fù)制代碼 代碼如下:

if (!(bufsize % sizeof(int)))

應(yīng)該被寫成

復(fù)制代碼 代碼如下:

if ((bufsize % sizeof(int)) == 0)

這樣可以反映這個(gè)測試的數(shù)值(非布爾)本質(zhì)。一個(gè)常見的錯(cuò)誤點(diǎn)是使用strcmp測試字符串是否相同,這個(gè)測試的結(jié)果永遠(yuǎn)不應(yīng)該被放棄。比較好的方法是定義一個(gè)宏STREQ。

復(fù)制代碼 代碼如下:

    #define STREQ(a, b) (strcmp((a), (b)) == 0)

對謂詞或滿足下面約束的表達(dá)式,非零測試經(jīng)常被放棄:

0表示假,其他都為真。
通過其命名可以看出返回真是顯而易見的。
用isvalid或valid稱呼一個(gè)謂詞,不要用checkvalid。

一個(gè)非常常見的實(shí)踐就是在一個(gè)全局頭文件中聲明一個(gè)布爾類型"bool"。這個(gè)特殊的名字可以極大地提高代碼可讀性。

復(fù)制代碼 代碼如下:

    typedef int    bool;
    #define FALSE    0
    #define TRUE    1


復(fù)制代碼 代碼如下:

    typedef enum { NO=0, YES } bool;

即便有了這些聲明,也不要檢查一個(gè)布爾值與1(TRUE,YES等)的相當(dāng)性;可用測試與0(FALSE,NO等)的不等性替代。絕大多數(shù)函數(shù)都可以保證為假的時(shí)候返回0,但為真的時(shí)候只返回非零。
復(fù)制代碼 代碼如下:

    if (func() == TRUE) { ...

必須被寫成
復(fù)制代碼 代碼如下:

    if (func() != FALSE) { ...

如果可能的話,最好為函數(shù)/變量重命名或者重寫這個(gè)表達(dá)式,這樣就可以顯而易見的知道其含義,而無需再與true或false比較了(例如,重命名為isvalid())。

嵌入賦值語句也有用武之地。在一些結(jié)構(gòu)中,在沒有降低代碼可讀性的前提下,沒有比這更好的方式來實(shí)現(xiàn)這個(gè)結(jié)果了。

復(fù)制代碼 代碼如下:

    while ((c = getchar()) != EOF) {
        process the character
    }

++和--操作符可算作是賦值語句。這樣,為了某些意圖,實(shí)現(xiàn)帶有副作用的功能。使用嵌入賦值語句也可能提高運(yùn)行時(shí)的性能。不過,大家應(yīng)該在提高的性能與下降的可維護(hù)性之間做好權(quán)衡。當(dāng)在一些人為的地方使用嵌入賦值語句時(shí),這種情況會(huì)發(fā)生,例如:
復(fù)制代碼 代碼如下:

    a = b + c;
    d = a + r;

不應(yīng)該被下面代碼替代:
復(fù)制代碼 代碼如下:

    d = (a = b + c) + r;

即使后者可能節(jié)省一個(gè)計(jì)算周期。在長期運(yùn)行時(shí),由于優(yōu)化器漸獲成熟,兩者的運(yùn)行時(shí)間差距將下降,而兩者在維護(hù)性方面的差異將提高,因?yàn)槿祟惖挠洃洉?huì)隨著時(shí)間的流逝而衰退。

在任何結(jié)構(gòu)良好的代碼中,goto語句都應(yīng)該保守地使用。使用goto帶來好處最大的地方是從switch、for和while多層嵌套中跳出,但這樣做的需求也暗示了代碼的內(nèi)層結(jié)構(gòu)應(yīng)該被抽取出來放到一個(gè)單獨(dú)的返回值為成功或失敗的函數(shù)中。

復(fù)制代碼 代碼如下:

        for (...) {
            while (...) {
                ...
                if (disaster)
                    goto error;

            }
        }
        ...
    error:
        clean up the mess

當(dāng)需要goto時(shí)候,其對應(yīng)的標(biāo)簽應(yīng)該被放在單獨(dú)一行,并且后續(xù)的代碼縮進(jìn)一級。使用goto語句時(shí)應(yīng)該增加注釋(可能放在代碼塊的頭)以說明它的功用和目的。continue應(yīng)該保守地使用,并且盡可能靠近循環(huán)的頂部。Break的麻煩比較少。

非原型函數(shù)的參數(shù)有時(shí)需要被顯式做類型提升。例如,如果函數(shù)期望一個(gè)32bit的長整型,但卻被傳入一個(gè)16bit的整型數(shù),可能會(huì)導(dǎo)致函數(shù)棧不對齊。指針,整型和浮點(diǎn)值都會(huì)發(fā)生此問題。


9. 復(fù)合語句

復(fù)合語句是一個(gè)由括號括起來的語句列表。有許多種常見的括號格式化方式。如果你有一個(gè)本地標(biāo)準(zhǔn),那請你與本地標(biāo)準(zhǔn)保持一致,或選擇一個(gè)標(biāo)準(zhǔn),并持續(xù)地使用它。在編輯別人的代碼時(shí),始終使用那些代碼中使用的樣式。

復(fù)制代碼 代碼如下:

control {
        statement;
        statement;
}

上面的風(fēng)格被稱為"K&R風(fēng)格",如果你還沒有找到一個(gè)自己喜歡的風(fēng)格,那么可以優(yōu)先考慮這個(gè)風(fēng)格。在K&R風(fēng)格中,if-else語句中的else部分以及do-while語句中的while部分應(yīng)該與結(jié)尾大括號在同一行中。而其他大部分風(fēng)格中,大括號都是單獨(dú)占據(jù)一行的。

當(dāng)一個(gè)代碼塊擁有多個(gè)標(biāo)簽時(shí),每個(gè)標(biāo)簽應(yīng)該單獨(dú)放在一行上。必須為C語言的switch語句的fall-through特性(即在代碼段與下一個(gè)case語句之前間沒有break)增加注釋以利于后期更好的維護(hù)。最好是lint風(fēng)格的注釋/指示。

復(fù)制代碼 代碼如下:

switch (expr) {
case ABC:
case DEF:
    statement;
    break;
case UVW:
    statement;
    /*FALLTHROUGH*/
case XYZ:
    statement;
    break;
}

這里,最后那個(gè)break是不必要的,但卻是必須的,因?yàn)槿绻罄m(xù)另外一個(gè)case添加到最后一個(gè)case的后面時(shí),它將阻止fall-through錯(cuò)誤的發(fā)生。如果使用default case,那么應(yīng)該該default case放在最后,且不需要break,如果它是最后一個(gè)case。

一旦一個(gè)if-else語句在if或else段中包含一個(gè)復(fù)合語句,if和else兩個(gè)段都應(yīng)該用括號括上(稱為全括號(fully bracketed)語法)。

復(fù)制代碼 代碼如下:

if (expr) {
    statement;
} else {
    statement;
    statement;
}

在如下面那樣的沒有第二個(gè)else的if-if-else語句序列里,括號也是不必可少的。如果ex1后面的括號被省略,編譯器解析將出錯(cuò):
復(fù)制代碼 代碼如下:

if (ex1) {
    if (ex2) {
        funca();
    }
} else {
    funcb();
}

一個(gè)帶else if的if-else語句在書寫上應(yīng)該讓else條件左對齊。
復(fù)制代碼 代碼如下:

if (STREQ (reply, "yes")) {
    statements for yes
    ...
} else if (STREQ (reply, "no")) {
    ...
} else if (STREQ (reply, "maybe")) {
    ...
} else {
    statements for default
    ...
}

這種格式看起來像一個(gè)通用的switch語句,并且縮進(jìn)反映了在這些候選語句間的精確切換,而不是嵌套的語句。

Do-while循環(huán)總是使用括號將循環(huán)體括上。

下面的代碼非常危險(xiǎn):

復(fù)制代碼 代碼如下:

#ifdef CIRCUIT
#    define CLOSE_CIRCUIT(circno)    { close_circ(circno); }
#else
#    define CLOSE_CIRCUIT(circno)
#endif

    ...
    if (expr)
        statement;
    else
        CLOSE_CIRCUIT(x)
    ++i;


注意,在CIRCUIT沒有定義的系統(tǒng)上,語句++i僅僅在expr是假的時(shí)候獲得執(zhí)行。這個(gè)例子指出宏用大寫命名的價(jià)值,以及讓代碼完全括號化的價(jià)值。

有些時(shí)候,通過break,continue,goto或return,if可以無條件地進(jìn)行控制轉(zhuǎn)移。else應(yīng)該是隱式的,并且代碼不應(yīng)該縮進(jìn)。

復(fù)制代碼 代碼如下:

if (level > limit)
    return (OVERFLOW)
normal();
return (level);

平坦的縮進(jìn)告訴讀者布爾測試在密封塊的其他部分是保持不變的。

10. 操作符

一元操作符不應(yīng)該與其唯一的操作數(shù)分開。通常,所有其他二元操作符都應(yīng)該使用空白與其操作樹分隔開,但'.'和'->'例外。當(dāng)遇到復(fù)雜表達(dá)式的時(shí)候我們需要做出一些判斷。如果內(nèi)層操作符沒有使用空白分隔而外層使用了,那么表達(dá)式也許會(huì)更清晰些。

如果你認(rèn)為一個(gè)表達(dá)式很難于閱讀,可以考慮將這個(gè)表達(dá)式拆分為多行。在接近中斷點(diǎn)的最低優(yōu)先級操作符處拆分是最好的選擇。由于C具有一些想不到的優(yōu)先級規(guī)則,混合使用操作符的表達(dá)式應(yīng)該使用括號括上。但是過多的括號也會(huì)使得代碼可讀性變差,因?yàn)槿祟惒簧瞄L做括號匹配。

二元逗號操作符也會(huì)被使用到,但通常我們應(yīng)該避免使用它。逗號操作符的最大用途是提供多元初始化或操作,比如在for循環(huán)語句中。復(fù)雜表達(dá)式,例如那些使用了嵌套三元?:操作符的表達(dá)式,可能引起困惑,并且應(yīng)該盡可能的避免使用。三元操作符和逗號操作符在一些使用宏的地方很有用,諸如getchar。在三元操作符?:前的邏輯表達(dá)式的操作數(shù)應(yīng)該被括起來,并且兩個(gè)子表達(dá)式的返回值應(yīng)該是相同類型。

11. 命名約定

毫無疑問,每個(gè)獨(dú)立的工程都有一套自己的命名約定,不過仍然有一些通用的規(guī)則值得參考。

1).為系統(tǒng)用途保留以下劃線開頭或下劃線結(jié)尾的名字,并且這些名字不應(yīng)該被用在任何用戶自定義的名字中。大多數(shù)系統(tǒng)使用這些名字用于用戶不應(yīng) 該也不需知道的名字中。如果你一定要使用你自己私有的標(biāo)識符,可以用標(biāo)識它們歸屬的包的字母作為開頭。
2).#define定義的常量名字應(yīng)該全部大寫。
3).Enum常量應(yīng)該大寫或全部大寫。
4).函數(shù)名、typedef名,變量名以及結(jié)構(gòu)體、聯(lián)合體與枚舉標(biāo)志的名字應(yīng)該用小寫字母。
5).很多"宏函數(shù)"都是全部大寫的。一些宏(諸如getchar和putchar)使用小寫字母命名,這事因?yàn)樗麄兛赡鼙划?dāng)成函數(shù)使用。只有在宏的行為類似一 個(gè)函數(shù)調(diào)用時(shí)才允許小寫命名的宏,也就是說它們只對其參數(shù)進(jìn)行一次求值,并且不會(huì)給具名形式參數(shù)賦值。有些時(shí)候我們無法編寫出一個(gè)具有函數(shù)行為的 宏,即使其參數(shù)也只是求值一次。
6).避免在同一情形下使用不同命名方式,比如foo和Foo。同樣避免foobar和foo_bar這種方式。需要考慮這樣所帶來的困惑。
7).同樣,避免使用看起來相似的名字。在很多終端以及打印設(shè)備上,'I'、'1'和'l'非常相似。給變量命名為l特別糟糕,因?yàn)樗雌饋硎窒癯A?1'。
通常,全局名字(包括enum)應(yīng)該具有一個(gè)統(tǒng)一的前綴,通過該前綴名我們可以識別出這個(gè)名字歸屬于哪個(gè)模塊。全局變量可以選擇匯集在一個(gè)全局結(jié) 構(gòu)中。typedef的名字通常在結(jié)尾加一個(gè)'t'。

避免名字與各種標(biāo)準(zhǔn)庫中的名字沖突。一些系統(tǒng)可能包含一些你所不需要的庫。另外你的程序?qū)砟程旌芸赡芤惨獢U(kuò)展。

12. 常量

數(shù)值型常量不應(yīng)該被硬編碼到源文件中。應(yīng)該使用C預(yù)處理器的#define特性為常量賦予一個(gè)有意義的名字。符號化的常量可以讓代碼具有更好的可讀性。在一處地方統(tǒng)一定義這些值也便于進(jìn)行大型程序的管理,這樣常量值可以在一個(gè)地方進(jìn)行統(tǒng)一修改,只需修改define的值即可。枚舉數(shù)據(jù)類型更適合聲明一組具有離散值的變量,并且編譯器還可以對其進(jìn)行額外的類型檢查。至少,任何硬編碼的值常量必須具有一段注釋,以說明該值的來歷。

常量的定義應(yīng)該與其使用是一致的;例如使用540.0作為一個(gè)浮點(diǎn)數(shù),而不是使用540外加一個(gè)隱式的float類型轉(zhuǎn)換。有些時(shí)候常量0和1被直接使用而沒有用define進(jìn)行定義。例如,一個(gè)for循環(huán)語句中用于標(biāo)識數(shù)組下標(biāo)的常量,

復(fù)制代碼 代碼如下:

for (i = 0; i < ARYBOUND; i++)

上面代碼是合理的,但下面代碼
復(fù)制代碼 代碼如下:

door_t *front_door = opens(door[i], 7);
if (front_door == 0)
    error("can't open %s\\\\n", door[i]);

是不合理的。在最后的那個(gè)例子中,front_door是一個(gè)指針。當(dāng)一個(gè)值是指針的時(shí)候,它應(yīng)該與NULL比較而不是與0比較。NULL被定義在標(biāo)準(zhǔn)I/O庫頭文件stdio.h中,在一些新系統(tǒng)中它在stdlib.h中定義。即使像1或0這樣的簡單值,我們最好也用define定義成TRUE和FALSE定義后再使用(有些時(shí)候,使用YES和NO可讀性更好)。

簡單字符常量應(yīng)該被定義成字面值,不應(yīng)該使用數(shù)字。不鼓勵(lì)使用非可見文本字符,因?yàn)樗鼈兪遣豢梢浦驳摹H绻强梢娢谋咀址直匾?,尤其是?dāng)它們在字符串中使用時(shí),它們應(yīng)該定義成三個(gè)八進(jìn)制數(shù)字的轉(zhuǎn)義字符(例如: '\007‘)而非一個(gè)字符。即使這樣,這種用法也應(yīng)該考慮其機(jī)器相關(guān)性,并按這里的方法處理。

13. 宏

復(fù)雜表達(dá)式可能會(huì)被用作宏參數(shù),這可能會(huì)因操作符優(yōu)先級順序而引發(fā)問題,除非宏定義中所有參數(shù)出現(xiàn)的位置都用括號括上了。對這種因參數(shù)內(nèi)副作用而引發(fā)的問題,我們似乎也無能為例,除了在編寫表達(dá)式時(shí)杜絕副作用(無論如何,這都是一個(gè)很好的主意)。如果可能的話,盡量在宏定義中對宏參數(shù)只進(jìn)行一次求值。有很多時(shí)候我們無法寫出一個(gè)可像函數(shù)一樣使用的宏。

一些宏也當(dāng)成函數(shù)使用(例如,getc和fgetc)。這些宏會(huì)被用于實(shí)現(xiàn)其他函數(shù),這樣一旦宏自身發(fā)生變化,使用該宏的函數(shù)也會(huì)受到影響。在交換宏和函數(shù)時(shí)務(wù)必要小心,因?yàn)楹瘮?shù)參數(shù)是按值傳遞的,而宏參數(shù)則是通過名稱替換。只有在宏定義時(shí)特別謹(jǐn)慎小心,才有可能減少使用宏時(shí)的擔(dān)心。

宏定義中應(yīng)該避免使用全局變量,因?yàn)槿肿兞康拿趾芸赡鼙痪植柯暶髡谏w。對于那些對具名參數(shù)進(jìn)行修改(不是這些參數(shù)所指向的存儲區(qū)域)或被用作賦值語句左值的宏,我們應(yīng)該添加相應(yīng)的注釋以給予提醒。那些不帶參數(shù)但引用變量,或過長或作為函數(shù)別名的宏應(yīng)該使用空參數(shù)列表,例如:

復(fù)制代碼 代碼如下:

#define    OFF_A()    (a_global+OFFSET)
#define    BORK()    (zork())
#define    SP3()    if (b) { int x; av = f (&x); bv += x; }

宏節(jié)省了函數(shù)調(diào)用和返回的額外開銷,但當(dāng)一個(gè)宏過長時(shí),函數(shù)調(diào)用和返回的額外開銷就變得微不足道了,這種情況下我們應(yīng)該使用函數(shù)。

在一些情況下,讓編譯器確保宏在使用時(shí)應(yīng)該以分號結(jié)尾是很有必要的。

復(fù)制代碼 代碼如下:

if (x==3)
    SP3();
else
    BORK();

如果省略SP3調(diào)用后面的分號,后面的else將會(huì)匹配到SP3宏中的那個(gè)if。有了分號,else分支就不會(huì)與任何if匹配。SP3宏可以這樣安全地實(shí)現(xiàn):
復(fù)制代碼 代碼如下:

#define SP3() \\\\
    do { if (b) { int x; av = f (&x); bv += x; }} while (0)

手工給宏定以加上do-while包圍看起來很別扭,而且很多編譯器和工具會(huì)抱怨在while條件是一個(gè)常量值。一個(gè)用來聲明語句的宏可以使得編碼更加容易:
復(fù)制代碼 代碼如下:

#ifdef lint
    static int ZERO;
#else
#    define ZERO 0
#endif
#define STMT( stuff )        do { stuff } while (ZERO)

我們可以用下面代碼來聲明SP3宏:
復(fù)制代碼 代碼如下:

#define SP3() \\\\
    STMT( if (b) { int x; av = f (&x); bv += x; } )

使用STMT宏可以有效阻止一些可以潛在改變程序行為的打印排版錯(cuò)誤。

除了類型轉(zhuǎn)換、sizeof以及上面那些技巧和手法,只有當(dāng)整個(gè)宏用括號括上時(shí)才應(yīng)該包含關(guān)鍵字。

14. 條件編譯

條件編譯在處理機(jī)器依賴、調(diào)試以及編譯階段設(shè)定特定選項(xiàng)時(shí)十分有用。不過要小心條件編譯。各種控制很容易以一種無法預(yù)料的方式結(jié)合在一起。如果使用#ifdef判斷機(jī)器依賴,請確保當(dāng)沒有機(jī)器類型適配時(shí),返回一個(gè)錯(cuò)誤,而不是使用默認(rèn)機(jī)器類型(使用#error并縮進(jìn)一級,這樣它可以一些老舊的編譯器下工作)。如果你#ifdef優(yōu)化選項(xiàng),默認(rèn)情況下應(yīng)該是一個(gè)未經(jīng)優(yōu)化的代碼,而不是一個(gè)不兼容的程序。確保測試的是未經(jīng)優(yōu)化的代碼。

注意在#ifdef區(qū)域內(nèi)的文本可能會(huì)被編譯器掃描(處理),即使#ifdef求值的結(jié)果為假。但即使文件的#ifdef部分永遠(yuǎn)不能被編譯到(例如,#ifdef COMMENT),這部分也不該隨意的放置文本。

盡可能地將#ifdefs放在頭文件中,而不是源文件中。使用#ifdef定義可以在源碼中統(tǒng)一使用的宏。例如,一個(gè)用于檢查內(nèi)存分配的頭文件可能這樣實(shí)現(xiàn):(省略了REALLOC和FREE):

復(fù)制代碼 代碼如下:

    #ifdef DEBUG
        extern void *mm_malloc();
    #    define MALLOC(size) (mm_malloc(size))
    #else
        extern void *malloc();
    #    define MALLOC(size) (malloc(size))
    #endif

條件編譯通常應(yīng)該基于一個(gè)接一個(gè)的特性的。多數(shù)情況下,都應(yīng)該避免使用機(jī)器或操作系統(tǒng)依賴。
復(fù)制代碼 代碼如下:

    #ifdef BSD4
        long t = time ((long *)NULL);
    #endif

上面代碼之所以糟糕有兩個(gè)原因:很可能在某個(gè)4BSD系統(tǒng)上有更好的選擇,并且也可能存在在某個(gè)非4BSD系統(tǒng)中上述代碼是最佳代碼。我們可以通過定義諸如TIME_LONG和TIME_STRUCTD等宏作為替代,并且在諸如config.h的配置文件中定義一個(gè)合適的宏。


15. 調(diào)試

"C代碼。C代碼運(yùn)行。運(yùn)行,代碼,運(yùn)行... 請運(yùn)行!!!" -- Barbara Tongue

如果你使用枚舉,第一個(gè)枚舉常量應(yīng)該是一個(gè)非零值,或者第一個(gè)常量應(yīng)該指示一個(gè)錯(cuò)誤。

復(fù)制代碼 代碼如下:

enum { STATE_ERR, STATE_START, STATE_NORMAL, STATE_END } state_t;
enum { VAL_NEW=1, VAL_NORMAL, VAL_DYING, VAL_DEAD } value_t;

未初始化的值后續(xù)將會(huì)自己獲取。

檢查所有錯(cuò)誤返回值,即使是那些"不能"失敗的函數(shù)的返回值??紤]即使之前所有的文件操作都已經(jīng)成功了,close()和fclose也可能失敗。編寫你自己的函數(shù),使得它們以一種明確的方式測試錯(cuò)誤、返回錯(cuò)誤碼或從程序中退出。包含大量調(diào)試和錯(cuò)誤檢查代碼,并把其中大多數(shù)留在最終的產(chǎn)品中。甚至檢查那些"不可能"的錯(cuò)誤。

使用assert機(jī)制保證傳給每個(gè)函數(shù)的值都是定義明確的,并且中間結(jié)果是形式良好的。

盡可能少的在調(diào)試代碼中使用#ifdef。例如,如果mm_malloc是一個(gè)調(diào)試用的內(nèi)存分配器,那么MALLOC將挑選合適的分配器,避免使用#ifdef在代碼中堆砌垃圾,并且使得分配之間的差異變得清晰,只是在調(diào)試期會(huì)分配些額外內(nèi)存。

復(fù)制代碼 代碼如下:

#ifdef DEBUG
#    define MALLOC(size)  (mm_malloc(size))
#else
#    define MALLOC(size)  (malloc(size))
#endif

對那些"不可能"溢出的對象做邊界校驗(yàn)。一個(gè)向變長存儲區(qū)寫入的函數(shù)應(yīng)該接受一個(gè)參數(shù)maxsize,該參數(shù)即目標(biāo)內(nèi)存區(qū)域的大小。如果有時(shí)候目標(biāo)內(nèi)存區(qū)域大小未知,一些maxsize的"魔數(shù)"值應(yīng)該意味著"沒有邊界檢查"。當(dāng)邊界檢查失敗,請確保這個(gè)函數(shù)做一些有用的事情,諸如退出程序或返回一個(gè)錯(cuò)誤狀態(tài)。
復(fù)制代碼 代碼如下:

/*
 * INPUT: A null-terminated source string `src' to copy from and
 * a `dest' string to copy to.  `maxsize' is the size of `dest'
 * or UINT_MAX if the size is not known.  `src' and `dest' must
 * both be shorter than UINT_MAX, and `src' must be no longer than
 * `dest'.
 * OUTPUT: The address of `dest' or NULL if the copy fails.
 * `dest' is modified even when the copy fails.
 */
    char *
copy (dest, maxsize, src)
    char *dest, *src;
    unsigned maxsize;
{
    char *dp = dest;

    while (maxsize\-\- > 0)
        if ((*dp++ = *src++) == '\\\\0')
            return (dest);

    return (NULL);
}


總之,記住一個(gè)程序產(chǎn)生錯(cuò)誤答案的速度快兩倍(譯注:是否有南轅北轍的意味),實(shí)則是變得無限緩慢,這個(gè)道理對那些偶爾崩潰或打擊有效數(shù)據(jù)的程序同樣成立。


相關(guān)文章

  • C++實(shí)現(xiàn)LeetCode(73.矩陣賦零)

    C++實(shí)現(xiàn)LeetCode(73.矩陣賦零)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(73.矩陣賦零),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C中qsort快速排序使用實(shí)例

    C中qsort快速排序使用實(shí)例

    在學(xué)習(xí)C++ STL的sort函數(shù),發(fā)現(xiàn)C中也存在一個(gè)qsort快速排序,要好好學(xué)習(xí)下C的庫函數(shù)啊
    2014-01-01
  • C語言完數(shù)的實(shí)現(xiàn)示例

    C語言完數(shù)的實(shí)現(xiàn)示例

    C語言中的完數(shù)指的是一個(gè)正整數(shù),本文主要介紹了C語言完數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • C++ Assert()斷言機(jī)制原理以及使用方法

    C++ Assert()斷言機(jī)制原理以及使用方法

    下面小編就為大家?guī)硪黄狢++ Assert()斷言機(jī)制原理以及使用方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • C語言中對文件最基本的讀取和寫入函數(shù)

    C語言中對文件最基本的讀取和寫入函數(shù)

    這篇文章主要介紹了C語言中對文件最基本的讀取和寫入函數(shù),是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-08-08
  • C++如何保存bmp圖片

    C++如何保存bmp圖片

    這篇文章主要介紹了C++如何保存bmp圖片問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C++中套接字庫sockpp的使用詳解

    C++中套接字庫sockpp的使用詳解

    sockpp是一個(gè)開源、簡單、現(xiàn)代的C++套接字庫,這篇文章主要為大家詳細(xì)介紹一下套接字庫sockpp的使用,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下
    2023-11-11
  • C++ Boost Heap使用實(shí)例詳解

    C++ Boost Heap使用實(shí)例詳解

    Boost是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱。Boost庫是一個(gè)可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱
    2022-11-11
  • C++?Date類的具體使用(構(gòu)建,重載等)

    C++?Date類的具體使用(構(gòu)建,重載等)

    本文主要介紹了C++?Date類的具體使用(構(gòu)建,重載等),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • c語言顏色代碼詳解

    c語言顏色代碼詳解

    在本篇文章里小編給大家整理的是關(guān)于c語言顏色代碼的知識點(diǎn)內(nèi)容,需要的朋友們可以參考下。
    2020-02-02

最新評論