2009-05-25 110 views
7

我只希望下似乎沒有你喜歡的冗餘嘰裏咕嚕:)
無論如何,有是:風格問題

for (p = fmt; *p; p++) { 
    if (*p != '%') { 
     putchar(*p); 
     continue; 
    } 
    switch (*++p) { 
     /* Some cases here */ 
     ... 
    } 
} 

我不知道爲什麼作家(Kernighan/Ritchie)在if聲明中使用了continue
我認爲這僅僅是因爲他認爲這將比在else聲明下縮進整個switch更優雅,您怎麼看?

回答

15

也許吧。人腦的堆棧空間有限,難以處理深度嵌套結構。任何使我們預期解析的信息變得平坦的東西使得它更易於理解。

同樣,我通常比較喜歡這樣的:

bool foo(int arg) 
{ 
    if(!arg) { 
     /* arg can't be 0 */ 
     return false; 
    } 

    /* Do some work */ 
    return true; 
} 

要這樣:

bool foo(int arg) 
{ 
    if(!arg) { 
     /* arg can't be 0 */ 
     return false; 
    } else { 
     /* Do some work */ 
     return true; 
    } 
} 

或者更糟的是,這樣的:

bool foo(int arg) 
{ 
    if(arg) { 
     /* Do some work */ 
     return true; 
    } else { 
     /* arg can't be 0 */ 
     return false; 
    } 
} 

在最後一個例子,但這部分這項工作可能會很長。當讀者到達else子句時,他可能不記得他是如何到達那裏的。

將保釋條件放在接近開始的位置有助於確保嘗試調用函數的人員對函數期望的輸入有一個很好的瞭解。

另外,正如其他人指出的那樣,continue指出,不需要進一步閱讀循環內的代碼,以確定是否在該點之後進行了更多的處理,從而使代碼更容易遵循。再次強調,讀者追蹤的東西越少越好。

1

總是有很多方法來編寫這樣的代碼 -

把整個交換機的else語句內將是非常有效的。我想他們這樣做的原因〜可能只是他們當時的想法:

「如果p的值不等於'%',則繼續。

如果你有一個其他的開關,它可能不是一個明顯的作家,你跳到下一個迭代在這種特定情況下。

雖然這完全是個人風格的選擇。我不會太擔心 - 只要以對你和你的團隊最有意義的方式寫就。

1

我同意。但是你不能把它看作是「單純的原因」,它實際上是一個很好的理由,因爲它減少了代碼的複雜性。使其更短,更易於閱讀和理解。

2

當它像這樣放置時,閱讀起來非常容易。

我們是通過循環完成這個循環嗎?是嗎?所以讓我們繼續與下一次迭代。

+1

這是有爭議的 - 這取決於這個習慣用法在你的代碼中是否常見。如果不是,它有一個不尋常的方法來控制一個循環,以及一個潛在的維護問題/缺陷源。 – 2009-05-25 20:22:07

+0

是的,這是非常正確的。不習慣這種習語的人在面對維護時可能會感到困惑。這正是我習慣的,啓發式教給我的更好。我很容易迷失在嵌套的if-then-else塊中,然後注意到休息;或繼續; – 2009-05-25 23:03:17

1

如果使用的是else然後裏面的東西被縮進else需求:

if() 
{ 
    doA(); 
} 
else 
{ 
    doB(); 
    if() 
    { 
    doC(); 
    } 
    else 
    { 
    doD() 
    } 
} 

如果使用continue那麼你就需要縮進:

if() 
{ 
    doA() 
    continue; 
} 
doB(); 
if() 
{ 
    doC(); 
    continue; 
} 
doD(); 

而且,continue手段我可以停止考慮這種情況:例如,如果我看到else,那麼在循環後面可能會有更多的'%'案例的處理,即在的末尾聲明;而在看到continue我立即知道,循環中'%'案件的處理已完成。

1

最可能的原因是後面的switch相當長 - 這看起來像printf格式解析。

2

我認爲他會有足夠的理由讓開關下的代碼縮進,並且縮進這個函數的整個內容是非常浪費水平空間的。在編寫代碼時,我想80個字符寬度仍然很受歡迎。

我不認爲這很難理解,但我確實認爲很高興提到你不立即做,然後GTFO。

9

因爲繼續,很明顯代碼是爲這個循環迭代完成的。如果使用了別的東西,你還必須檢查else之後是否沒有代碼。

我認爲儘快退出上下文通常是一種好習慣,因爲這會導致代碼更加清晰。


例如:

if(arg1 == NULL) 
    return; 

if(arg2 == NULL) 
    return; 

//Do some stuff 

if(arg1 != null) 
{ 
    if(arg2 != null) 
    { 
    //Do some stuff 
    } 
} 
+1

+1清除代碼。除此之外,當代碼稍後修改時,您不必考慮所有錯誤情況,因爲它們已經在頂部處理過了,您知道只需處理有效的情況。我覺得用這種方式編寫代碼是非常優雅的 - 具有「其他」版本的經驗以及它是我其他公司的標準 - 例如只有一個回報的東西... – stefanB 2009-05-26 01:00:43

1

可能會有更大的一個原因繼續/打破循環。所以它看起來未來:

loop 
{ 
    if (cond1) 
    { 
     if (cond2) 
     { 
     if (cond2) 
     { 
      more conditions... 
     } 
     } 
    } 
    else 
    { 
     the loop action 
    } 
} 

恕我直言,這不是那麼優雅和可讀性爲你的榜樣循環,例如:

loop 
{ 
    if (cond1) 
     continue; 
    if (cond2) 
     continue; 
    if (cond2) 
     continue; 
    if(more conditions...) 
     continue; 

    the loop action 
} 

而且你甚至不需要了解所有「所有結構如果「(它可能更復雜)理解循環邏輯。

P.S.只是爲了這種情況:我不認爲作者想過如何編寫這個循環,他們只是寫了:)

-2

那麼,我寫了C程序約11年,我不得不讀了5次你的一塊代碼來理解它!

Kernighan和裏奇在六十年代活躍。那時,能夠理解一段代碼並不相關。能夠編寫適合16 Ko的代碼是。

所以我不感到驚訝。C是一種可怕的語言,當你的teatchers是K & R.看看realloc:誰會知道類似今天的代碼?在60年代,它是所有的憤怒,但它現在是可怕的,至少:o)

+2

K&R出現在1978年,而不是20世紀60年代,通常被認爲是一個非常好的作品,簡潔而且寫得很好。代碼的清晰度高度相關:在十年前的1968年北約軟件工程大會上,與會者一致認爲軟件變得如此複雜以至於出現了「軟件危機」。正在討論的代碼示例使用非常常見的C(和C++)習語。 – 2009-05-25 21:04:43

0

我堅持迪傑斯特拉的教導:轉到是有害的。繼續/休息是goto的小兄弟。

如果問題在於您過多縮進了代碼,解決方案並沒有在循環中繼續,而是通過分離不同功能中的代碼或考慮更好的組織方式來降低複雜性。

例如,@Kamarey片斷甚至會像這樣清晰的:

loop 
{ 
    if (!(cond1 || 
     cond2 || 
     cond2 || 
     ...)) 
    { 
     the loop actions; 
    } 
} 

或@Ori Pessach例如可以表達,如:

bool foo(int arg) 
{ 
    if(arg) { 
     /*do some work*/ 
    } 

    return arg != 0; 
} 

簡單,平時我找不到一個足夠好的理由使用非結構化編程結構(也許在一些非常有限的情況下清理代碼...)