是否有可能用while
和if
聲明替換if/else
聲明(說我們正在使用C語言)?如果可能的話,能否請你舉個例子。所以,說我有替換if/else與while/if語句
if (cond1)
exec1
else
exec2
我真的想擺脫if/else
的,只是使用if/while
結構。
Turing Complete語言是否足以讓while/if
語句(用於控制流)?
我該怎麼做if/else
構造?
(這是不是一個作業,這是出於好奇)
是否有可能用while
和if
聲明替換if/else
聲明(說我們正在使用C語言)?如果可能的話,能否請你舉個例子。所以,說我有替換if/else與while/if語句
if (cond1)
exec1
else
exec2
我真的想擺脫if/else
的,只是使用if/while
結構。
Turing Complete語言是否足以讓while/if
語句(用於控制流)?
我該怎麼做if/else
構造?
(這是不是一個作業,這是出於好奇)
這些都是等價的,如果cond1
不exec1
改變。
if (cond1) exec1 else exec2
if (cond1) exec1
if (!cond1) exec2
沒有時間需要。
它有點笨重,但假設任一分支的執行不改變的條件下,你可以替換的if-else與一對夫婦田地的構建: 假定原來是:
if (cond) {
exec1();
else {
exec2();
}
if (cond) {
exec1();
}
if (!cond) {
exec2();
}
或用while
S::
if
s內更換 使用
如果::3210
你甚至都不需要while
,你只需要能夠比較並能夠分支,換句話說,if
和goto
。在下面的程序,功能test_normally()
和test_subnormally()
是等價的:
#include <stdio.h>
void exec1(void)
{
puts("exec1() called");
}
void exec2(void)
{
puts("exec2() called");
}
void exec3(void)
{
puts("exec3() called");
}
void test_normally(void)
{
int cond1 = 0;
int cond2 = 1;
int i = 5;
/* First if test */
if (cond1)
exec1();
else
exec2();
puts("First if test over.");
/* Second if test */
if (cond2)
exec1();
else
exec2();
puts("Second if test over.");
/* While test */
while (i > 0) {
exec3();
--i;
}
puts("Loop test over.");
}
void test_subnormally(void)
{
int cond1 = 0;
int cond2 = 1;
int i = 5;
/* First if test */
if (!cond1)
goto cond1_false;
exec1();
goto cond1_end;
cond1_false:
exec2();
cond1_end:
puts("First if test over.");
/* Second if test */
if (!cond2)
goto cond2_false;
exec1();
goto cond2_end;
cond2_false:
exec2();
cond2_end:
puts("Second if test over.");
/* While test */
loop_start:
if (!(i > 0))
goto loop_end;
exec3();
--i;
goto loop_start;
loop_end:
puts("Loop test over.");
}
int main(void)
{
test_normally();
putchar('\n');
test_subnormally();
return 0;
}
輸出:
[email protected]:~/src/sandbox$ ./goto
exec2() called
First if test over.
exec1() called
Second if test over.
exec3() called
exec3() called
exec3() called
exec3() called
exec3() called
Loop test over.
exec2() called
First if test over.
exec1() called
Second if test over.
exec3() called
exec3() called
exec3() called
exec3() called
exec3() called
Loop test over.
[email protected]:~/src/sandbox$
通過比較這兩個功能,希望你可以看到爲什麼if
和while
和他們所有的朋友都好比替代品。
test_subnormally()
實際上與您的C源代碼編譯爲機器代碼之後處理器實際上非常接近。下面是test_normally()
在64位Intel處理器的組件輸出的gcc - 你可以看到,有幾乎是彙編指令和用於其他功能的C源之間的一對一的映射,test_subnormally()
:
.LC3:
.string "First if test over."
.LC4:
.string "Second if test over."
.LC5:
.string "Loop test over."
.text
.globl test_normally
.type test_normally, @function
test_normally:
.LFB3:
.cfi_startproc # // Function entry
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0, -8(%rbp) # // -8(%rbp) is cond1
movl $1, -12(%rbp) # // -12(%rbp) is cond2
movl $5, -4(%rbp) # // -4(%rbp) is i
cmpl $0, -8(%rbp) # if (!cond1)
je .L5 # goto cond1_false;
call exec1 # exec1();
jmp .L6 # goto cond1_end;
.L5: # cond1_false:
call exec2 # exec2();
.L6: # cond1_end:
movl $.LC3, %edi # // move "First if test over" to %edi
call puts # puts("First if test over");
cmpl $0, -12(%rbp) # if (!cond2)
je .L7 # goto cond2_false;
call exec1 # exec1();
jmp .L8 # goto cond2_end;
.L7: # cond2_false:
call exec2 # exec2();
.L8: # cond2_end:
movl $.LC4, %edi # // move "Second if test over" to %edi
call puts # puts("Second if test over");
jmp .L9 # goto loop_start;
.L10: # loop_body:
call exec3 # exec3();
subl $1, -4(%rbp) # --i;
.L9: # loop_start:
cmpl $0, -4(%rbp) # if (!(i > 0)) ...
jg .L10 # ...goto loop_body;
movl $.LC5, %edi # // move "Loop test over" to %edi
call puts # puts("Loop test over");
leave # // Function exit
.cfi_def_cfa 7, 8
ret
.cfi_endproc
編譯器在這裏選擇將循環片段的順序略有不同,但除此之外它幾乎完全像C源代碼test_subnormally()
。我們擁有if
和while
以及他們在C中的朋友的深層原因正是這樣,我們不必編寫看起來像這樣的代碼,但簡單程度和類似意大利麪條的代碼就是處理器最終執行的代碼(並且你需要的是圖靈完整的),所以我們有一個編譯器將一些看起來更容易理解和可維護的東西轉化爲處理器完全滿意的混亂狀態。
對於一般的更換if() ... else ...
結構,你可以緩存條件的結果:
int condition = cond1;
if(condition) exec1;
if(!condition) exec2;
這樣,你避免cond1
和exec1
有副作用的問題。
關於你對圖靈完備性問題:
正如保羅·格里菲思指出,if()
和goto
就足夠了。然而,if()
和遞歸也是如此。您可以使用自遞歸函數替換任何while(cond1) exec1;
循環:
void loopy(/*whatever state the loop touches*/) {
if(cond1) {
exec1;
loopy(/*pass on the current state*/);
}
}
這一事實在像Lisp和計劃功能的語言被大量濫用。當你學習這些語言的編程時,你會被教導以這種方式編寫你的遞歸(尾遞歸),以至於編譯器會發現你打算編寫一個循環並相應地進行優化...
除非這是爲了用於某些代碼高爾夫我不明白爲什麼你想這樣做。另外我沒有看到使用某種while循環結構實現'else'分支的方法。 if-then分支是,但不是其他分支。 – datenwolf 2014-10-04 16:58:51
if-else可以被switch-case和conditional操作符替換。 – 2014-10-04 17:00:43