无限循环的"for(;;)"习语是否正确归因于 PDP-11 C 编译器?

Is "for(;;)" idiom for infinite loop correctly attributed to PDP-11 C compiler?

本文关键字:PDP-11 归因于 编译器 习语 for 无限循环 是否      更新时间:2023-10-16

最近我发现了一篇文章,该文章声称在无限循环中选择for(;;)而不是while(1)的想法是因为PDP-11上最初可用的C编译器为while(1)生成了额外的机器指令。

顺便说一句,现在甚至Visual c++的警告也倾向于前者。

for(;;)成语的这种归因有多现实?

在最初的K&R中明确提到了"for(;;)"习语。这对我来说就足够了

谨防某些"感性归因",因为往往是由于缺乏上下文而导致的假消息来源。OP将消息标记为C和c++。

现在,K&R可以是C历史的半神,但肯定不能被认为是c++的权威。此外,编译器优化可以在c++中发挥基本作用,但C系统程序员经常认为这是"滥用"(他们喜欢将C视为"带有表达式的汇编程序",而不是"高级语言")。

现在的编译器很可能会生成完全相同的代码(这很容易证明),使用其中一个或另一个更多的是品味问题,而不是其他。

在这个意义上,我倾向于for(;;),因为我可以很容易地把它读成"for-ever",而while(true)读成"而这个真实的东西是真实的",让你弄清楚如果它甚至可能是假的... .浪费了2毫秒的大脑!(但这是我的个人意见:我知道很多人不得不考虑for(;;)而不是while(true))

然而,我也能认出它们都是"图像表示"(不实际阅读文本,只是通过摄影记忆看看它们是什么样子),指向同一个智力概念(待在这里直到有人把你从里面踢出去)。

关于MS警告,有时它可以避免您编写错误的表达式(如true||a)。但是显然被滥用了,不应该出现在里面没有操作的琐碎表达式中。在这两种情况下,MS编译器都会生成相同的机器码。也许给微软的反馈会让他们在未来的版本中对这个警告不那么乏味。

以下是V7 Unix编译器cc生成的结果(使用SIMH和来自TUHS的图像):

$ cat>a.c
main(){
 while(1);
}
$ cat>b.c
main(){
 for(;;);
}
$ cc -S a.c
$ cc -S b.c

a.c (while)编译为:

.globl  _main
.text
_main:
~~main:
jsr     r5,csv
jbr     L1
L2:L4:tst       $1
jeq     L5
jbr     L4
L5:L3:jmp       cret
L1:jbr  L2
.globl
.data

b.c (for)变成:

.globl  _main
.text
_main:
~~main:
jsr     r5,csv
jbr     L1
L2:L4:jbr       L4
L5:L3:jmp       cret
L1:jbr  L2
.globl
.data

所以for(;;)在不使用优化的情况下编译到更少的指令是正确的。然而,当使用-O编译时,两个程序产生的完全是相同的程序集:

.globl  _main
.text
_main:
~~main:
jsr     r5,csv
L4:jbr  L4
.globl
.data

,当我添加一个printf("Hello");的循环体时,程序仍然是一样的。

所以,这个习语可能起源于PDP-11机器语言,但到1979年,这种差异已经在很大程度上无关重要了。

我不知道这是不是真的,但是文章的说法是明智的和现实的。for(;;)while(1)更短

我想你会发现K&R并没有编写PDP-11编译器,因为PDP-11是一个"机器"(而不是一种语言),它已经为自己的PDP-11指令集拥有了自己的MACRO汇编器。

K&R{据说)写了他们自己的'C'编译器…嗯. .如果它必须是宏,不是吗(因为这是PDP上唯一可用的指令集汇编器),然后(据说)用'C'编写Unix,因为他们认为他们可以比DEC的PDP-11操作系统(RT-11和RSTS-11)做得更好。他们可能是对的!

for(;;)是惯用的,所以如果你的代码只有经验丰富的C程序员才能阅读,那就太好了。while(true)对于没有经验的程序员和非C程序员来说更容易理解。前者还依赖于一些不明显的行为,即空布尔表达式的计算结果为true。基于这些原因,如果你必须选择一个,我会说选择后者。

然而我认为在几乎所有的实际情况下,程序员都不希望代码永远循环。希望循环终止总是有原因的,即使只是用户点击了control-C。不需要无限循环