2014-10-04 258 views
2

是否有可能用whileif聲明替換if/else聲明(說我們正在使用C語言)?如果可能的話,能否請你舉個例子。所以,說我有替換if/else與while/if語句

if (cond1) 
    exec1 
else 
    exec2 

我真的想擺脫if/else的,只是使用if/while結構。

Turing Complete語言是否足以讓while/if語句(用於控制流)?

我該怎麼做if/else構造?

(這是不是一個作業,這是出於好奇)

+0

除非這是爲了用於某些代碼高爾夫我不明白爲什麼你想這樣做。另外我沒有看到使用某種while循環結構實現'else'分支的方法。 if-then分支是,但不是其他分支。 – datenwolf 2014-10-04 16:58:51

+1

if-else可以被switch-case和conditional操作符替換。 – 2014-10-04 17:00:43

回答

0

這些都是等價的,如果cond1exec1改變。

if (cond1) exec1 else exec2 

if (cond1) exec1 
if (!cond1) exec2 

沒有時間需要。

1

它有點笨重,但假設任一分支的執行不改變的條件下,你可以替換的if-else與一對夫婦田地的構建: 假定原來是:

if (cond) { 
    exec1(); 
else { 
    exec2(); 
} 

if (cond) { 
    exec1(); 
} 
if (!cond) { 
    exec2(); 
} 

或用while S::

它可以只 if s內更換 使用 如果::3210
0

的如果,否則可以替換

如果(條件COND1爲true) {

執行exec1;

}

//如果條件爲假

{ 執行exec2((條件COND1爲真)!);使用

}

雖然循環:

而(條件COND1爲true) {

執行exec1;

}

while(!(條件cond1爲真))//條件爲假

{ execute exec2;

}

+2

您忘記了休息時間,否則您的時間不會停止 – sqlab 2014-10-04 17:24:23

+0

不,不會在每次迭代時檢查條件,條件也會在while循環內被修改。對於例如迭代器++; – ABcDexter 2014-10-05 18:04:42

1

你甚至都不需要while,你只需要能夠比較並能夠分支,換句話說,ifgoto。在下面的程序,功能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$ 

通過比較這兩個功能,希望你可以看到爲什麼ifwhile和他們所有的朋友都好比替代品。

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()。我們擁有ifwhile以及他們在C中的朋友的深層原因正是這樣,我們不必編寫看起來像這樣的代碼,但簡單程度和類似意大利麪條的代碼就是處理器最終執行的代碼(並且你需要的是圖靈完整的),所以我們有一個編譯器將一些看起來更容易理解和可維護的東西轉化爲處理器完全滿意的混亂狀態。

2

對於一般的更換if() ... else ...結構,你可以緩存條件的結果:

int condition = cond1; 
if(condition) exec1; 
if(!condition) exec2; 

這樣,你避免cond1exec1有副作用的問題。

關於你對圖靈完備性問題:
正如保羅·格里菲思指出,if()goto就足夠了。然而,if()和遞歸也是如此。您可以使用自遞歸函數替換任何while(cond1) exec1;循環:

void loopy(/*whatever state the loop touches*/) { 
    if(cond1) { 
     exec1; 
     loopy(/*pass on the current state*/); 
    } 
} 

這一事實在像Lisp和計劃功能的語言被大量濫用。當你學習這些語言的編程時,你會被教導以這種方式編寫你的遞歸(尾遞歸),以至於編譯器會發現你打算編寫一個循環並相應地進行優化...