亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
123下一頁
最近訪問板塊 發(fā)新帖
查看: 17893 | 回復(fù): 21
打印 上一主題 下一主題

[C] switch-case 非常規(guī)用法拾零 (1. 絕無原創(chuàng) 2. 非常重視代碼規(guī)范者勿入) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2010-12-17 00:25 |只看該作者 |倒序瀏覽
0. 前言
以下介紹的兩個大牛都是利用了 switch 語句中的 case 部分可以置于一個
block (通常是 if{} 或 while{} 塊)中, switch 語句執(zhí)行一個直接跳轉(zhuǎn)進(jìn)入該
block,進(jìn)入該 block 的條件有時候被有意地忽略。

全文思路和代碼絕無原創(chuàng)之處,只是略加整理了一下。更詳細(xì)的請看提供的鏈接。
希望高手老鳥們指出錯誤不足并給出更深入的分析,如果能提出比例子更漂亮的
方案就太棒了(我感覺可以用回調(diào)函數(shù)一類的方法實現(xiàn)協(xié)作過程,不過還沒細(xì)想)。

代碼規(guī)范的討論就請免了,Simon Taham 在文章里說了一段話挺有趣:

Any coding standard which insists on syntactic clarity at the expense
of algorithmic clarity should be rewritten. If your employer fires you
for using this trick, tell them that repeatedly as the security staff
drag you out of the building. hahaha

論壇徽章:
0
2 [報告]
發(fā)表于 2010-12-17 00:25 |只看該作者
本帖最后由 vupiggy 于 2010-12-16 17:31 編輯

1. Duff's device (原創(chuàng) Tom Duff)
http://en.wikipedia.org/wiki/Duff%27s_device

下面一段小程序:

  1. do {
  2.     *to++ = *from++;
  3. } while (--count > 0);
復(fù)制代碼
這段程序最讓大牛們不爽的是,每拷貝一個字節(jié)就需要完成和拷貝字節(jié)同量級甚
至更耗時的減法及比較操作,一個可能的優(yōu)化是減少循環(huán)次數(shù),即在一次減法和
比較之后批處理拷貝幾個字節(jié),可能的代碼如下:

  1. do {
  2.     *to++ = *from++;
  3.     *to++ = *from++;
  4.     *to++ = *from++;
  5.     *to++ = *from++;
  6.     *to++ = *from++;
  7.     *to++ = *from++;
  8.     *to++ = *from++;
  9.     *to++ = *from++;
  10. } while ((count -= 8) > 0);
復(fù)制代碼
這段代碼是錯的,當(dāng)且僅當(dāng) count 被 8 整除才工作,這個思路總體是正確的,
但最大的挑戰(zhàn)是如何處理余數(shù)。Tom 大叔巧妙的解決余數(shù)問題,代碼如下:

  1. int n = (count + 7) / 8;
  2. switch (count % 8) {
  3.         case 0:        do {  *to++ = *from++;
  4.         case 7:              *to++ = *from++;
  5.         case 6:              *to++ = *from++;
  6.         case 5:              *to++ = *from++;
  7.         case 4:              *to++ = *from++;
  8.         case 3:              *to++ = *from++;
  9.         case 2:              *to++ = *from++;
  10.         case 1:              *to++ = *from++;
  11.                        } while (--n > 0);
  12. }
復(fù)制代碼
過程一開始,switch 語句計算余數(shù),直接跳轉(zhuǎn)到對應(yīng) case 地址,妙處就在除了
case 0,所有的 case 都在 do {} while() 中,第一次拷貝 count % 8 個
字節(jié),之后邏輯由 do {} while() 循環(huán)負(fù)責(zé),一次循環(huán)拷貝 8 個字節(jié)直至結(jié)束。

注: 例子其實是 Stroustrup 的新手友好版本而不是 Tom 大叔的原始版本,但
是非常接近。這個版本可以再精簡一點點,拋棄變量 n,將 while(--n > 0) 改
  1. while ((count -= 8) > 0)
復(fù)制代碼

論壇徽章:
0
3 [報告]
發(fā)表于 2010-12-17 00:26 |只看該作者
本帖最后由 vupiggy 于 2010-12-16 17:31 編輯

2. Simon Tatham's Coroutines in C (原創(chuàng) putty的作者 Simon Tatham)
這位牛牛要解決的問題復(fù)雜一些,即所謂“協(xié)作過程”(coroutine)問題。
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

2.1 引子
考慮如下函數(shù):

  1. int function(void) {
  2.     int i;
  3.     for (i = 0; i < 10; i++)
  4.         return i;   /* won't work, but wouldn't it be nice? */
  5. }
復(fù)制代碼
以上函數(shù)的本意是向調(diào)用者依次返回從0到9,很顯然結(jié)果是每一次都返回了0,
將 i 聲明為 static 也無濟(jì)于事。一個可行的方案是:

  1. int function(void) {
  2.     static int i, state;

  3.     switch(state) {
  4.         case 0: goto LABEL0;
  5.         case 1: goto LABEL1;
  6.     }

  7.     /* start of function */
  8. LABEL0:
  9.     for (i = 0; i < 10; i++) {
  10.         state = 1;
  11.         return i;
  12. LABEL1:; /* Resume control straight after return */
  13.     }
  14. }
復(fù)制代碼
以上代碼最嚴(yán)重的問題是當(dāng)有多點返回的時候,程序員要手工維護(hù)跳轉(zhuǎn)的標(biāo)簽及
一一對應(yīng)的 case 段。利用上面提到的 case 段可以置于塊內(nèi)的特點,上面的函
數(shù)可以改寫成:

  1. int function(void) {
  2.     static int i, state = 0;

  3.     switch (state) {
  4.         case 0: /* start of function */

  5.         for (i = 0; i < 10; i++) {
  6.             state = 1; /* so we will come back to "case 1" */
  7.             return i;

  8.             case 1:; /* resume control straight after the return */
  9.         }
  10.     }
  11. }
復(fù)制代碼
再進(jìn)一步提高代碼可讀性,使用幾個宏:

  1. #define crBegin static int state=0; switch(state) { case 0:
  2. #define crReturn(i,x) do { state=i; return x; case i:; } while (0)
  3. #define crFinish }

  4. int function(void) {
  5.     static int i;

  6.     crBegin;

  7.     for (i = 0; i < 10; i++)
  8.         crReturn(1, i);

  9.     crFinish;
  10. }
復(fù)制代碼
這下看上去像一個“正常”的 C 程序了吧 還有一個小問題,程序員還要自己想
法保證 crReturn() 的第一個參數(shù)是唯一的,煩!接著 hack,把這個宏定義成
這個樣子利用編譯器來幫我們保證參數(shù)唯一:

  1. #define crReturn(x) do { state=__LINE__; return x; case __LINE__:; } while (0)
復(fù)制代碼
搞掂曬,程序員的重要品質(zhì)就是能偷懶就偷懶,能不手工(眼工)做的就不做。

2.2 協(xié)作過程
在編寫 putty 的過程中,這個大牛發(fā)明了上述用法來解決所謂協(xié)作過程的問題。
考慮以下兩個例程:

  1. /* Decompression code */
  2. int decompressor(void) {
  3.     while (1) {
  4.         c = getchar();
  5.         if (c == EOF)
  6.             break;
  7.         if (c == 0xFF) {
  8.             len = getchar();
  9.             c = getchar();
  10.             while (len--)
  11.                 emit(c);
  12.         } else
  13.             emit(c);
  14.     }
  15.     emit(EOF);
  16. }
復(fù)制代碼

  1. /* Parser code */
  2. void parser(int c) {
  3.     while (1) {
  4.         c = getchar();
  5.         if (c == EOF)
  6.             break;
  7.         if (isalpha(c)) {
  8.             do {
  9.                 add_to_token(c);
  10.                 c = getchar();
  11.             } while (isalpha(c));
  12.             got_token(WORD);
  13.         }
  14.         add_to_token(c);
  15.         got_token(PUNCT);
  16.     }
  17. }
復(fù)制代碼
姑且把解壓例程理解為生產(chǎn)者而語法解析例程為消費者,如果不考慮使用管道,
多線程等重量級解決方案,那么必然有函數(shù)調(diào)用關(guān)系,姑且是認(rèn)為解析例程調(diào)用
解壓例程,也就是把解析例程中的每一個 getchar() 替換成 decompressor(),
并把 decompressor() 中的每一個 emit 替換成 return。但是問題來了,每一
次調(diào)進(jìn) decompressor 以后,總是從頭開始執(zhí)行,這不滿足要求,正確的行為應(yīng)
該是每次調(diào)進(jìn) decompressor() 都從上一次 return 的地方繼續(xù)執(zhí)行,否則就不
叫協(xié)作了。采用引子里提到的三個宏構(gòu)建一個狀態(tài)機(jī)即可完美解決協(xié)作需求:

  1. int decompressor(void) {
  2.     static int c, len;
  3.     crBegin;
  4.     while (1) {
  5.         c = getchar();
  6.         if (c == EOF)
  7.             break;
  8.         if (c == 0xFF) {
  9.             len = getchar();
  10.             c = getchar();
  11.             while (len--)
  12.                 crReturn(c);
  13.         } else
  14.             crReturn(c);
  15.     }
  16.     crReturn(EOF);
  17.     crFinish;
  18. }
復(fù)制代碼
用 cpp 來預(yù)處理一下可以幫助理解。

論壇徽章:
0
4 [報告]
發(fā)表于 2010-12-17 00:28 |只看該作者
3 后記

向大牛們致敬,他們的奇思妙想給我們帶來了無盡的樂趣,引用一句俗得不能再俗
的話和各位同好共勉:have a lot of fun

題外話,這個版事實上大多在討論和 C/C++ 本身無關(guān)的話題,諸如網(wǎng)絡(luò)編程,系
統(tǒng)編程,多線程多進(jìn)程一類的其實都和 C/C++ 沒什么關(guān)系。是不是可以考慮增加
系統(tǒng)編程子版面,有關(guān)系統(tǒng)調(diào)用,同步,socket 編程的都丟過去。另外,orz,
真不好意思,前兩天我自己就把一個 Makefile 相關(guān)的東東丟在這個版里而不是
它本來應(yīng)該在的shell版。

論壇徽章:
1
2015年辭舊歲徽章
日期:2015-03-03 16:54:15
5 [報告]
發(fā)表于 2010-12-17 10:13 |只看該作者
coroutine 這個解決方案真牛!

論壇徽章:
2
青銅圣斗士
日期:2015-11-26 06:15:59數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-07-24 06:20:00
6 [報告]
發(fā)表于 2010-12-17 11:32 |只看該作者
本帖最后由 OwnWaterloo 于 2010-12-17 11:33 編輯

我感覺這方案沒能解決。

1. coroutine的目的是為了在特定點掛起, 并在隨后(按掛起時的狀態(tài))恢復(fù)執(zhí)行

掛起時的狀態(tài)需要保存, 而例子中, 是保存在static變量中。

2. static變量的問題

使用static變量, 就帶有static變量的所有壞處 —— 當(dāng)然, 這不是重點。
重點是, 無法建立2個coroutine。

舉個lua的例子:

function f()
  print('step1')
  coroutine.yield()
  print('step2)
end

可以同時創(chuàng)建1個以上的corotuine:

c1 = coroutine.create(f)
c2 = coroutine.create(f)

并且按任意順序執(zhí)行2個coroutine中的4個step, 比如:
coroutine.resume(c1) -- 執(zhí)行第1個的step1
coroutine.resume(c2) -- 執(zhí)行第2個的step1
coroutine.resume(c2) -- 執(zhí)行第2個的step2
coroutine.resume(c1) -- 執(zhí)行第1個的step1

用static來保存context顯然做不到這點。

例子中的decompressor和parser因為static的限制, 都是一次性的。
一個進(jìn)程中, decompressor只能使用一次。


3. coroutine可以在掛起時, 可以順帶返回一個值。

這樣, coroutine就可以用于實現(xiàn)generator。
但這同時需要有一個方法, 判斷coroutine是否執(zhí)行完畢。

還是以lua舉例:

function g()
  coroutine.yield()
  coroutine.yield(12)
  coroutine.yield(3,26)
end

c = coroutine.create(g)
=coroutine.resume(c) --> true
=coroutine.resume(c) --> true, 12
=coroutine.resume(c) --> true, 3, 26
=coroutine.resume(c) --> false —— 執(zhí)行完畢

lua是可以返回多個值, 所以利用第1個返回值來代表coroutine是否執(zhí)行完畢。
python也可以返回多個值。  但我印象中, python是通過拋出異常來表示coroutine執(zhí)行完畢。

總之, 需要一種方式來表示coroutine是yield還是return。


例子顯然也做不到這點, function產(chǎn)生10個返回值之后, 結(jié)果是什么?
如果我沒看錯, 結(jié)果應(yīng)該是跳出for循環(huán), 執(zhí)行到switch的尾 } , 然后函數(shù)在沒有return的情況下返回。
這是否是未定義行為我忘了, 但至少得不到一個確定的返回值。



綜上, coroutine的關(guān)鍵點:
1. 保存執(zhí)行的context —— 用static, 并帶來static的各種問題
2. 提供一種機(jī)制區(qū)分yield和return —— 沒有解決
這個方案都沒能很好解決。

充其量, 這方案僅僅是讓語法稍微好看那么一點。

對簡單的應(yīng)用, 搞那么復(fù)雜不如直接在外部寫一個for循環(huán)。
對復(fù)雜的應(yīng)用, 這種方案又不具備范化的可能。

論壇徽章:
224
2022北京冬奧會紀(jì)念版徽章
日期:2015-08-10 16:30:32操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-02-18 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-03-01 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-03-02 06:20:0015-16賽季CBA聯(lián)賽之上海
日期:2019-09-20 12:29:3219周年集字徽章-周
日期:2019-10-01 20:47:4815-16賽季CBA聯(lián)賽之八一
日期:2020-10-23 18:30:5320周年集字徽章-20	
日期:2020-10-28 14:14:2615-16賽季CBA聯(lián)賽之廣夏
日期:2023-02-25 16:26:26CU十四周年紀(jì)念徽章
日期:2023-04-13 12:23:1015-16賽季CBA聯(lián)賽之四川
日期:2023-07-25 16:53:45操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-05-10 19:22:58
7 [報告]
發(fā)表于 2010-12-17 12:28 |只看該作者
這些代碼非常漂亮,
為什么要說不尊重代碼規(guī)范呢??

論壇徽章:
224
2022北京冬奧會紀(jì)念版徽章
日期:2015-08-10 16:30:32操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-02-18 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-03-01 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-03-02 06:20:0015-16賽季CBA聯(lián)賽之上海
日期:2019-09-20 12:29:3219周年集字徽章-周
日期:2019-10-01 20:47:4815-16賽季CBA聯(lián)賽之八一
日期:2020-10-23 18:30:5320周年集字徽章-20	
日期:2020-10-28 14:14:2615-16賽季CBA聯(lián)賽之廣夏
日期:2023-02-25 16:26:26CU十四周年紀(jì)念徽章
日期:2023-04-13 12:23:1015-16賽季CBA聯(lián)賽之四川
日期:2023-07-25 16:53:45操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-05-10 19:22:58
8 [報告]
發(fā)表于 2010-12-17 12:32 |只看該作者
不明白為什么有的coder喜歡用宏


這玩意玩不起,,,太強(qiáng)大了

論壇徽章:
0
9 [報告]
發(fā)表于 2010-12-17 14:20 |只看該作者
對簡單的應(yīng)用, 搞那么復(fù)雜不如直接在外部寫一個for循環(huán)。
對復(fù)雜的應(yīng)用, 這種方案又不具備范化的可能。
OwnWaterloo 發(fā)表于 2010-12-17 11:32



    學(xué)習(xí)了.

論壇徽章:
0
10 [報告]
發(fā)表于 2010-12-17 14:32 |只看該作者
mark下
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP