Re: [問題] *p++ = *q++

看板C_and_CPP (C/C++)作者 (Cattuz)時間3周前 (2026/01/29 01:34), 編輯推噓13(1308)
留言21則, 13人參與, 1周前最新討論串3/3 (看更多)
※ 引述《ttucse ((((>( ̄▽ ̄)<))))》之銘言: : 我只有學過java : c跟c++學得很爛 : 現在都寫java : 所以我指標也很爛 : 我在BSD UNIX的作者Bill Joy的演講 : 看到這個*p++ = *q++ : 圖在這裡 : http://i.imgur.com/3QSwcbZ.jpg
: https://youtu.be/rByrD_R9Vuo
: 影片的19分44秒左右投影片上的程式碼 : 所以想問*p++ = *q++ : 是什麼意思 : 還是這個寫法不好 : 可是這個是BSD UNIX作者給的 : 讓我很想知道這個的意思 : 謝謝大家 這是經典的寫法,也算半個時代的眼淚了 這段程式碼最著名的出處不是別的, 正是大名鼎鼎的K&R C 換句話說,對現在五六十歲的資工系教授那一輩的人 這個應該是教科書等級的寫法 XD https://meee.com.tw/jWInyox 截圖是K&R中譯版的相關內容,我手上這本是蔡文能副教授翻的 小弟也算有幸在他退休前跑去旁聽他的計科概,不過這是題外話:P 對大多數人比較舒服的寫法可能會像推文裡面說的 用一個index i去處理遞增動作: int i = 0; while(s[i]!='\0'){ t[i] = s[i]; i++; } 那為什麼K&R要在一本基礎教學書秀這種要一點功底才能懂的寫法? (K&R甚至比影片內的更兇殘,它是放在while的判斷條件裡) 除去它更加簡練,或是可以展現C語言語法的綜合應用這種理由以外 其實我猜更大的原因應該是Dennis Ritchie的私心XD 如果對電腦的發展史有一點理解的話 應該知道上面影片講的PDP-11、Unix跟C語言是大約同一個時代出現的產物 而PDP-11的手冊不知道哪個老教授留的, 總之現在還可以在mit cs的網頁挖到: https://pdos.csail.mit.edu/6.828/2005/readings/pdp11-40.pdf 其中的第三章就在介紹PDP-11的addressing mode 跟多數人(比方說我)比較熟悉的x86/x64架構比的話, 你會發現他有一個很特別的東西 叫做autoincrement-addressing mode 簡單的說PDP的指令集允許你設定指令中的某幾個bit 把要操作的register作為記憶體位置看待 然後在你對記憶體位置上的東西做完該做的操作之後 他會自動去把register的值+1 (或是-1) 隨便舉個例子: r0 = 0x1234->"Foo" r1 = 0x5678->"Bar" movb (r1)+ , (r0)+ (註:(rn)+代表autoincrement-addressing mode) 上面這行組語做完後 記憶體位置0x1234上的第一個byte會被0x5678上的值蓋過去 0x1234->"Boo" 0x5678->"Bar" 並且: r0 = 0x1235->oo r1 = 0x5679->ar 你稍微想一下就會發現 *s++=*t++; 跟上面這行組語不能說很像,只能說做的事情一模一樣 換句話說在PDP-11上面, 這個看起來很複雜的expression可以直接被一行組語幹掉 (如果再考慮當年的compiler沒現在那麼威的分析能力 這沒準還會是同語意下唯一可以只編成一行的寫法...) K&R C的第一版成書於1978年 1978年的另一件大事,叫做Intel推出8086處理器 也就是現代x86_64處理器的開山鼻祖,後來的事情大家都知道了 作為幾乎可以跟PC劃上等號的指令集架構 x86並沒有支援這麼fancy的addressing mode 同一行程式碼在x86上應該是要編兩個mov + 兩個inc來做這件事 不管你把++拆開來寫還是塞在同一行都一樣 所以這段code自然就只剩下精簡程式碼的功能,而失去了最佳化的能力 (當然現代x64有SIMD跟一些針對連續記憶體處理的指令,那就是後話了) 但說是這麼說 工程師就是會對自己搞出來的得意之作念念不忘的生物 就像高老爺子非得在他的TAOCP裡面塞磁帶的外部排序算法一樣 K&R C的第二版於1989年出版,也就是我現在手上拿的這個版本 1989年我想應該已經沒PDP-11什麼事情了 但K&R還是選擇展示這段程式碼作為strcpy的實作 也許多少有緬懷那個年代的意義在吧 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.192.202.202 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1769621660.A.99D.html

01/29 02:00, 3周前 , 1F
感謝講解。
01/29 02:00, 1F

01/29 09:25, 3周前 , 2F
推好文
01/29 09:25, 2F

01/29 14:38, 3周前 , 3F
01/29 14:38, 3F

01/29 15:43, 3周前 , 4F
01/29 15:43, 4F

01/29 19:49, 2周前 , 5F
01/29 19:49, 5F

01/29 20:16, 2周前 , 6F
推好文
01/29 20:16, 6F

01/29 20:23, 2周前 , 7F
原來還有這段歷史
01/29 20:23, 7F

01/30 15:50, 2周前 , 8F
01/30 15:50, 8F

01/30 16:44, 2周前 , 9F
01/30 16:44, 9F

01/30 16:52, 2周前 , 10F
x86 其實是有一個老組語指令 MOVS 有類似的效果啦
01/30 16:52, 10F

01/30 16:53, 2周前 , 11F
MOVS 把 ds:esi 搬到 es:edi 之後把 esi 和 edi 都遞增/減
01/30 16:53, 11F

01/30 16:54, 2周前 , 12F
(易記指令是 Move String 搬字串,因為加 REP 可以搬一串)
01/30 16:54, 12F

01/30 16:55, 2周前 , 13F
但它是限定只能用這組暫存器,不像 PDP-11 能用其他暫存器
01/30 16:55, 13F

01/30 16:56, 2周前 , 14F
所以在已經很有壓力的 x86 暫存器數量下不容易最佳化出它來
01/30 16:56, 14F

01/30 17:00, 2周前 , 15F
然後 REP MOVS 因為是數量先行指定 (REP 用 ecx 倒數計數)
01/30 17:00, 15F

01/30 17:01, 2周前 , 16F
所以應該只有例如 memcpy 這種有指定數量的能生出 REP MOVS
01/30 17:01, 16F

01/30 17:02, 2周前 , 17F
零結尾字串用的 strcpy 用 MOVS 應該沒有省到什麼東西
01/30 17:02, 17F

02/01 05:56, 2周前 , 18F
好文推
02/01 05:56, 18F

02/03 14:08, 2周前 , 19F
總是有真正的高手解惑,受益良多
02/03 14:08, 19F

02/04 18:43, 2周前 , 20F
好像在不知道哪家的小眾dsp看過類似的指令 一樣是帶+1
02/04 18:43, 20F

02/10 14:04, 1周前 , 21F
02/10 14:04, 21F
文章代碼(AID): #1fUaYScT (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1fUaYScT (C_and_CPP)