用while / if语句替换if / else

时间:2014-10-04 16:56:07

标签: c if-statement while-loop

是否可以用if/elsewhile语句替换if语句(例如,我们在C中工作)?如果有可能,请您分享一个例子。所以,说我有

if (cond1)
    exec1
else 
    exec2

我真的想摆脱if/else并且只使用if/while构造。

图灵完备语言是否足以拥有while/if语句(对于控制流程)?

如何使用if/else构造进行此操作?

(这不是作业,这是出于好奇)

5 个答案:

答案 0 :(得分:2)

对于if() ... else ...构造的一般替换,您可以缓存条件的结果:

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

这样可以避免cond1exec1中的副作用问题。

关于你关于完整性的问题:
正如Paul Griffiths指出的那样,if()goto就足够了。但是,if()和递归也是如此。您可以使用自递归函数替换任何while(cond1) exec1;循环:

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

这个事实在像lisp和scheme这样的函数式语言中被滥用。当你学习这些语言的编程时,你会被教导以这样的方式编写递归(尾递归),编译器可以知道你打算写一个循环并相应地进行优化......

答案 1 :(得分:1)

它有些笨重,但假设任一分支的执行都没有改变条件,你可以用几个while替换if-else构造: 假设原文是:

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

只能用if s替换:

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

while s:

while (cond) {
    exec1();
    break;
}
while (!cond) {
    exec2();
    break;
}

答案 2 :(得分: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;
}

并输出:

paul@local:~/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.
paul@local:~/src/sandbox$ 

通过比较这两个功能,希望你能看出为什么ifwhile以及他们所有的朋友都比其他选择更好。

在将C源编译成机器代码之后,

test_subnormally()实际上非常接近处理器实际执行的操作。这是来自64位英特尔处理器上gcc的test_normally()的汇编输出 - 您可以看到汇编指令和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

编译器在这里选择以稍微不同的顺序放置循环片段,但除了它之外,它几乎完全像test_subnormally()的C源。我们拥有ifwhile以及他们在C中的朋友的根本原因恰恰是我们不必编写看起来像这样的代码,但这种简单程度和意大利面 - 像代码是处理器最终最终执行的(并且你需要完成图灵完成),所以我们有一个编译器将一些看起来更容易理解和可维护的东西变成处理器完全满意的那种混乱

答案 3 :(得分:0)

如果cond1中没有更改exec1,则这些是等效的。

if (cond1) exec1 else exec2

if (cond1) exec1
if (!cond1) exec2

不需要。

答案 4 :(得分:0)

if,else可以替换为: 使用如果

if(条件cond1为真)  {

执行exec1;

}

if(!(条件cond1为真))//条件为假

{   执行exec2;

}

使用循环:

while(条件cond1为真)  {

执行exec1;

}

while(!(条件cond1为真))//条件为假

{   执行exec2;

}