![](/img/trans.png)
[英]In a type trait, why do people use enum rather than static const for the value?
[英]Is “for(;;)” faster than “while (TRUE)”? If not, why do people use it?
for (;;) {
//Something to be done repeatedly
}
我已經看到這種東西經常使用,但我認為它很奇怪......說while(true)
或類似的東西不是更清楚嗎?
我猜(這也是許多程序員求助於神秘代碼的原因)這會快一點嗎?
為什么,真的值得嗎? 如果是這樣,為什么不這樣定義它:
#define while(true) for(;;)
我更喜歡for(;;)
有兩個原因。
一是一些編譯器在while(true)
上產生警告(類似於“循環條件是恆定的”)。 避免警告總是一件好事。
另一個是我認為for(;;)
更清晰,更有說服力。 我想要一個無限循環。 它的字面沒有條件,這取決於什么。 我只是想讓它永遠持續下去,直到我做點什么來擺脫它。
而對於while(true)
,那么 true 與任何事情有什么關系呢? 我對循環不感興趣,直到 true 變為 false,這就是這種形式的字面意思(在 true 為 true 時循環)。 我只想循環。
不,絕對沒有性能差異。
我個人使用for (;;)
因為里面沒有任何數字,它只是一個關鍵字。 我更喜歡while (true)
, while (1)
, while (42)
, while (!0)
等。
因為丹尼斯·里奇
我開始使用for (;;)
是因為 Dennis Ritchie 在 K&R 中就是這樣做的,在學習一門新語言時,我總是試圖模仿聰明人。
這是慣用的 C/C++。 如果您計划在 C/C++ 領域做很多事情,從長遠來看習慣它可能會更好。
您的#define
將不起作用,因為被 #define'd 的東西必須看起來像一個 C 標識符。
所有現代編譯器都會為這兩種結構生成相同的代碼。
在任何健全的編譯器中它肯定不會更快。 它們都將被編譯成無條件跳轉。 for 版本更容易輸入(正如 Neil 所說),如果您了解 for 循環語法,就會很清楚。
如果你很好奇,這里是 gcc 4.4.1 為我提供的 x86。 兩者都使用 x86 JMP指令。
void while_infinite()
{
while(1)
{
puts("while");
}
}
void for_infinite()
{
for(;;)
{
puts("for");
}
}
編譯為(部分):
.LC0:
.string "while"
.text
.globl while_infinite
.type while_infinite, @function
while_infinite:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
.L2:
movl $.LC0, (%esp)
call puts
jmp .L2
.size while_infinite, .-while_infinite
.section .rodata
.LC1:
.string "for"
.text
.globl for_infinite
.type for_infinite, @function
for_infinite:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
.L5:
movl $.LC1, (%esp)
call puts
jmp .L5
.size for_infinite, .-for_infinite
我更喜歡for (;;)
因為它在不同的類 C 語言中是最一致的。
在 C++ 中while (true)
很好,但在 C 中你依賴於一個頭文件來定義true
,但TRUE
也是一個常用的宏。 如果您使用while (1)
它在 C 和 C++ 以及 JavaScript 中是正確的,但在 Java 或 C# 中是正確的,它們要求循環條件為布爾值,例如while (true)
或while (1 == 1)
。 在 PHP 中,關鍵字不區分大小寫,但該語言更喜歡大寫TRUE
。
但是, for (;;)
在所有這些語言中總是完全正確的。
我個人更喜歡for (;;)
習語(它將編譯為與while (TRUE)
相同的代碼。
使用while (TRUE)
在某種意義上可能更具可讀性,我決定使用for (;;)
習語,因為它很突出。
一個無限循環結構應該很容易在代碼中被注意到或調用,我個人認為for (;;)
風格比while (TRUE)
或while (1)
更好。
另外,我記得當 while 循環的控制表達式是一個常量時,一些編譯器會發出警告。 我不認為這種情況發生得太多,但只是虛假警告的可能性就足以讓我想要避免它。
我見過有些人喜歡它,因為他們在這樣的地方有一個#define:
#define EVER ;;
這允許他們寫這個:
for (EVER)
{
/* blah */
}
怎么樣(如果您的語言支持):
start:
/* BLAH */
goto start;
生成的機器代碼沒有區別。
然而,為了逆勢而上,我認為 while(TRUE) 形式比 for(;;) 更具可讀性和直觀性,並且可讀性和清晰度是編碼指南的重要原因,而不是我的任何原因我聽說過 for(;;) 方法(我更喜歡將我的編碼指南建立在可靠的推理和/或有效性證明的基礎上)。
如果您的代碼由編譯器優化,兩者應該相同。 為了解釋我所說的優化是什么意思,這里有一個用 MSVC 10 編寫的示例代碼:
int x = 0;
while(true) // for(;;)
{
x +=1;
printf("%d", x);
}
如果您在 Debug 模式下構建它(沒有任何優化 (/Od) ),反匯編顯示了明顯的區別。 while
的true
條件有額外的說明。
while(true)
00D313A5 mov eax,1 //extra
00D313AA test eax,eax //extra
00D313AC je main+39h (0D313B9h) //extra
{
x +=1;
00D313AE mov eax,dword ptr [x]
00D313B1 add eax,1
00D313B4 mov dword ptr [x],eax
printf("%d", x);
...
}
00D313B7 jmp main+25h (0D313A5h)
for(;;)
{
x +=1;
00D213A5 mov eax,dword ptr [x]
00D213A8 add eax,1
00D213AB mov dword ptr [x],eax
printf("%d", x);
...
}
00D213AE jmp main+25h (0D213A5h)
但是,如果您在發布模式下構建代碼(使用默認的最大化速度 (/O2) ),您將獲得相同的輸出。 兩個循環都減少為一條跳轉指令。
for(;;)
{
x +=1;
01291010 inc esi
printf("%d", x);
...
}
0129101C jmp main+10h (1291010h)
while(true)
{
x +=1;
00311010 inc esi
printf("%d", x);
...
}
0031101C jmp main+10h (311010h)
無論您使用哪種方式,對於速度優化的體面編譯器來說都無關緊要。
不僅是一個眾所周知的模式,而且是 C(和 C++)中的標准習語
while(true)
使用 Visual Studio 生成警告(條件不變)。 我工作過的大多數地方都編譯生產版本,警告為錯誤。 所以
for(;;)
是首選。
這是個人喜好的問題,哪種方式更快。 就我個人而言,我是一名觸摸打字員,在編程期間從不看我的鍵盤——我可以觸摸鍵盤上的所有 104 個鍵。
我發現輸入“while (TRUE)”是否更快。
我在心里添加了一些手指運動測量值並將它們加總。 “for(;;)”有大約 12 個鍵寬的前后移動(在 Home 鍵和鍵之間,以及 Home 鍵和 SHIFT 鍵之間)“while (TRUE)”有大約 14 個鍵寬的后退和移動第四。
但是,我在輸入后者時不太容易出錯。 我在精神上一次用文字思考,所以我發現輸入諸如“nIndex”之類的東西比諸如“nIdx”之類的首字母縮寫詞更快,因為我必須真正在心里拼出字母而不是在我的腦海中說出它並讓我的手指自動- 輸入單詞(如騎自行車)
(我的 TypingTest.com 基准測試 = 136 WPM)
所有好的答案 - 行為應該完全相同。
但是 - 假設它確實有所作為。 假設其中一個每次迭代多執行 3 條指令。
你應該關心嗎?
僅當您在循環內執行的操作幾乎為零時,情況幾乎從未如此。
我的觀點是,有微觀優化和宏觀優化。 微優化就像“理發減肥”。
for(;;Sleep(50))
{
// Lots of code
}
比以下更清楚:
while(true)
{
// Lots of code
Sleep(50);
}
如果您不使用Sleep()
,這並不適用。
我無法想象一個有價值的編譯器會生成任何不同的代碼。 即使這樣做了,如果不測試更有效的特定編譯器,就無法確定。
但是我建議你更喜歡for(;;)
,原因如下:
我使用過的一些編譯器會為 while(true) 生成一個常量表達式警告,並帶有適當的警告級別設置。
在您的示例中,宏 TRUE 可能沒有按照您的預期定義
無限 while 循環有許多可能的變體,例如while(1)
、 while(true)
、 while(1==1)
等; 所以for(;;)
可能會導致更大的一致性。
“永遠”循環在嵌入式系統中作為后台循環很流行。 有些人將其實現為:
for (; ;)
{
// Stuff done in background loop
}
有時它被實現為:
while (TRUE /* or use 1 */)
{
// Stuff done in background loop
}
還有一個實現是:
do
{
// Stuff done in background loop
} while (1 /* or TRUE */);
優化編譯器應該為這些片段生成相同或相似的匯編代碼。 一個重要的注意事項:循環的執行時間不是一個大問題,因為這些循環永遠持續下去,而且更多的時間花在處理部分。
我認為 while(true) 比 for(;;) 更具可讀性——看起來程序員在 for 循環中遺漏了一些東西:)
使用“for(;;)”的最重要原因是在進行探索性編程時害怕使用“while(TRUE)”。 使用“for”更容易控制重復次數,並且更容易將“for”循環轉換為無限循環。
例如,如果您正在構建一個遞歸函數,您可以在轉換為無限循環之前限制對該函數的調用量。
for(int i=0;i<1000;i++) recursiveFunction(oneParam);
當我確定我的功能時,我將其轉換為無限循環:
for(;;) recursiveFunction(oneParam);
正如其他人指出的那樣,從技術角度來看,這根本無關緊要。 有些人認為一種比另一種更具可讀性,並且他們對此有不同的看法。
對我來說,這基本上只是吹毛求疵,因為任何 C 程序員都應該能夠立即將while(1)
和for(;;)
識別為無限循環。
您的定義將不起作用。 但是,您可以(但不應該)這樣做:
#define repeat for(;;)
int main(void)
{
repeat {
puts("Hello, World");
}
}
但真的,不要做那樣的事情......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.