作者sarafciel (Cattuz)
看板C_and_CPP
标题Re: [问题] *p++ = *q++
时间Thu Jan 29 01:34:10 2026
※ 引述《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://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1769621660.A.99D.html
1F:推 ttucse: 感谢讲解。 01/29 02:00
2F:推 lc85301: 推好文 01/29 09:25
3F:推 hongsiangfu: 推 01/29 14:38
4F:推 james732: 推 01/29 15:43
5F:推 goldie: 推 01/29 19:49
6F:推 if4: 推好文 01/29 20:16
7F:推 Richun: 原来还有这段历史 01/29 20:23
8F:推 agogoman: 推 01/30 15:50
9F:推 LPH66: 推 01/30 16:44
10F:→ LPH66: x86 其实是有一个老组语指令 MOVS 有类似的效果啦 01/30 16:52
11F:→ LPH66: MOVS 把 ds:esi 搬到 es:edi 之後把 esi 和 edi 都递增/减 01/30 16:53
12F:→ LPH66: (易记指令是 Move String 搬字串,因为加 REP 可以搬一串) 01/30 16:54
13F:→ LPH66: 但它是限定只能用这组暂存器,不像 PDP-11 能用其他暂存器 01/30 16:55
14F:→ LPH66: 所以在已经很有压力的 x86 暂存器数量下不容易最佳化出它来 01/30 16:56
15F:→ LPH66: 然後 REP MOVS 因为是数量先行指定 (REP 用 ecx 倒数计数) 01/30 17:00
16F:→ LPH66: 所以应该只有例如 memcpy 这种有指定数量的能生出 REP MOVS 01/30 17:01
17F:→ LPH66: 零结尾字串用的 strcpy 用 MOVS 应该没有省到什麽东西 01/30 17:02
18F:推 mihonisizumi: 好文推 02/01 05:56
19F:推 HolyBugTw: 总是有真正的高手解惑,受益良多 02/03 14:08
20F:推 chuegou: 好像在不知道哪家的小众dsp看过类似的指令 一样是带+1 02/04 18:43
21F:推 F04E: 推 02/10 14:04