什么是達夫設備(Duff's Device)


在看《你必須知道的496個C語言問題》一書中,提到"達夫設備"這個東西,主要是下面的代碼:

register n = (count + 7) / 8; /\* count > 0 assumed \*/

switch (count % 8)

{

case 0: do { \*to = \*from++;

case 7: \*to = \*from++;

case 6: \*to = \*from++;

case 5: \*to = \*from++;

case 4: \*to = \*from++;

case 3: \*to = \*from++;

case 2: \*to = \*from++;

case 1: \*to = \*from++;

} while (--n > 0);

}

這是個很棒的迂回循環展開法, 由 Tom Duff 在 Lucasfilm 時所設計。它的 ``傳統" 形態, 是用來復制多個字節。

這里 count 個字節從 from 指向的數組復制到 to 指向的內存地址 (這是個內存映射的輸出寄存器, 這也是為什么它沒有被增加)。它把 swtich 語句和復制 8 個字節的循環交織在一起, 從而解決了剩余字節的處理問題 (當 count 不是 8 的倍數時)。相信不相信, 象這樣的把 case 標志放在嵌套在 swtich 語句內的模塊中是合法的。當他公布這個技巧給 C 的開發者和世界時, Duff 注意到 C 的 swtich 語法, 特別是 ``跌落" 行為, 一直是被爭議的, 而 ``這段代碼在爭論中形成了某種論據, 但我不清楚是贊成還是反對"

函數包含一個switch語句,它的case語句同時位於一個while循環體內(有一個case語句在外面)。switch內的表達式計算被八除的余數。執行開始於while循環內的哪個位置由這個余數決定,最終循環退出,(沒有break)。Duff's Device這樣就簡單漂亮地解決了邊界條件的問題。順便提一下,為什么"case 0"標記在循環外面呢?這樣不是打破了對稱的美觀嗎?這樣做的唯一理由是為了處理空序列。當余數為零,"case 0"內就需要執行一個多余的測試來判斷空序列的可能性。總之,這是個很酷的算法。

達夫設備是一個加速循環語句的C編碼技巧。其基本思想是--減少循環測試的執行次數。

如果在一個for循環中,其中操作執行得如果足夠快(比如說,一個賦值)——那么測試循環條件占用了循環所用時間的很大部分。循環應該被部分解開,這樣數個操作一次完成,測試操作也做的較少。其實,是通過switch語句將要進行的連續循環操作的次數進行了預判(根據擦case語句的位置)然后依次執行,而不必每次都去進行測試條件。

在這里Duff's Device是個新穎的,有創造力的解決方案。這里有一個使用該模型的一個實例:快速拷貝和填充。

Duff's Device對效率的負面影響可能來自於代碼膨脹(一些處理器更善於處理緊湊的循環而不是大的循環)和特別的結構。優化器被做成當遇一些更加技巧性的結構時可能會不知所措從而生成比較保守的代碼。

其實達夫設備是使用switch語句來控制進入循環的位置。

下面的程序是簡單驗證達夫設備的執行:

#include <stdio.h>

#include <stdlib.h>

int main(int argc,char**argv){

int n;

if(argc<2){

printf("not enough arugment\n");

return -1;

}

n=atoi(argv[1]);

switch(n){

case 0: do {printf("%d ",0);

case 1: printf("%d ",1);

case 2: printf("%d ",2);

case 3: printf("%d ",3);

case 4: printf("%d ",4);

}while(--n>0);

}

return 0;

}

從上面的輸出結果我們可以清楚的看到,switch語句控制了進入循環的位置。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM