同时执行if和else块

时间:2010-06-13 08:43:35

标签: c++ c conditional-statements

在C或C ++中

if ( x )
    statement1;
else
    statement2;

x的两个语句的执行值是什么?

我知道我们可以像这样一起执行if-else

if(1){
    goto ELSE;
}
else{
    ELSE:
}

有什么办法,比如价值吗? (我认为这是不可能的。问,因为有人争论!)

14 个答案:

答案 0 :(得分:24)

  

两个语句的执行值是什么?

仅在这种情况下(在类Unix系统上):

 pid_t  pid;
 pid = fork();
 if (pid == 0){
    //some code
 }
 else {
    //some code
 }

在这种情况下,两个分支将始终同时被调用(好吧,或多或少同时),但是在不同的过程中。

  

我知道我们可以像这样一起执行if-else:

此:

if(1){
    goto ELSE;
}
else{
    ELSE:
}

是一个错误的结构。你需要使用这样的东西:

if ( condition) {
    //some code here
    ...
}
... //some other code here

如果总是调用一个分支,那么你不需要“else”。

答案 1 :(得分:15)

  

两个语句的执行值是什么?

没有这样的值:值是评估为true(某些东西!= 0),还是评估为false)(0)。没有其他可能的值。

  

我知道我们可以像这样一起执行if-else:if(1){goto ELSE; } else {ELSE:}

虽然有效,但它根本不依赖于if条件的值。

答案 2 :(得分:4)

如果你不介意一些未定义的行为,你可以在C ++中这样做:

struct J {
  jmp_buf b;
};

struct backer {
  backer(int v):did(v) { }

  backer(backer const& o):j(o.j),did(o.did) { 
    o.did = true; 
  }

  ~backer() {
    if(!did) {
      longjmp(j.b, 1);
    }
  }

  operator bool() {
    return !did;
  }

  J j;
  mutable bool did;
};

int main() {
  if(backer b = setjmp(b.j.b)) {
    std::cout << "a";
  } else {
    std::cout << "b";
  }
}

这适用于GCC和Clang。它通过在setjmp中的缓冲区上调用b.j.b来工作。该缓冲区保存在一个类中,因为它可以是一个数组,只有将它们包装在一个类中才能复制数组。然后,backer的构造函数获取setjmp的返回值并使用它初始化did。在backer的析构函数中,该标志被测试,如果它是假的(首先返回setjmp),它会跳回并让setjmp返回非零值。当其中一个分支完成时,将调用backer的析构函数。

编译器可以自由复制在初始化backer时构造的b对象。如果发生这种情况,它的复制构造函数关心将did设置为true,确保我们只跳回一次,即使编译器在初始化期间没有优化backer副本。

因此程序打印ab

答案 3 :(得分:2)

在递归函数中,两个分支都可以执行:

void recursive(bool first)
{
    if(first)
    {
        recursive(false);
    }
    else
    {
        //END
    }
}

调用它
recursive(true)

将执行if分支,然后执行else分支

答案 4 :(得分:2)

首先,这不是一个愚蠢的问题:)

要理解为什么不能通过任何特殊技巧实现这一目标,我们需要逐步调试由if语句生成的程序集(特别是具有gcc 4.2.1的Intel处理器的程序集 - 不同架构将导致不同的组装。)

采用这个简单的C程序:

#include <stdio.h>

int main()
{
    int i;
    scanf("%d", &i);
    if (i == 8)
    {
        return 100;
    }
    else
    {
        return 3;
    }
}

如果用户输入非零整数,则返回100;否则我们返回3.实际情况在这里并不重要,因为我们只对main生成的汇编感兴趣:

        ; ...
        call    _scanf
        movl    -4(%rbp), %eax
        cmpl    $8, %eax
        jne     L2
        movl    $100, -20(%rbp)
        jmp     L4
L2:
        movl    $3, -20(%rbp)
L4:
        movl    -20(%rbp), %eax
        leave
        ret

我会假设你不了解装配 - 但不要担心,这个例子并不是很难跟上。这里发生的是我们call scanf,我们compare的结果(i)为8。

接下来,如果对标签L2进行J ot N质量指令,则会有E ump。这意味着如果i等于8,则执行以下指令:

  • 将3移至rbp
  • rbp移至eax
  • 离开(从而从程序中返回值3)。

但是,如果i 等于8,那么当我们点击jne指令时,我们就不会跳转。相反,我们:

  • 将100移至rbp
  • J u mp无条件地使用标签L4
  • rbp移至eax并最终从该计划返回100。

使用此处生成的程序集,实际上只有两个可能的分支。你不能随意重新排序代码。

那么是否可以执行两个分支(当它们不是return个语句时)?是的,条件是您的编译器无法正确生成分支代码。但这在生产级编译器上永远不会发生。

答案 5 :(得分:0)

没有狡猾的诡计,不,这是不可能的。考虑表达式的含义:

if (cond) {
  ifTrue;
} else {
  ifFalse;
}

如果ifTrue为真(非零值/ cond),则执行true,如果ifFalse为假,则执行cond (零/ false)。由于cond不能同时为真和假,因此如果没有特殊情况,则无法执行ifTrueifFalse,例如goto

答案 6 :(得分:0)

您可以使用整数作为测试变量,并使用&gt;,&lt;,&gt; =,&lt; =,==

检查其值
    int x = 0;

    if ( x >= 0 ) {
        statement 1;
    }
    if ( x <= 0 ) {
        statement 2;
    }

在这个例子中,只有当x为0时才执行这两个语句。否则只有其中一个。

答案 7 :(得分:0)

如果这是一个技巧问题,你可以用

回答
if( ({ statement2; 1; }) ) 
  statement1;
else
  statement2;

使用GCC语句表达式:)对于表达式语句,有逗号运算符

if(expr2, 1) 
  expr1;
else
  expr2;

这是quite popular question

答案 8 :(得分:0)

x没有单个值,条件语句的所有路径都将被执行(这是条件语句的 point 的一种形式) ;您希望基于x执行一个分支另一个分支。

...然而

在C(和C ++)中,您可以使用setjmp / longjmp工具来执行if - else的两个路径:

#include <setjmp.h>
#include <stdio.h>

jmp_buf Env;

int main(void)
{
  int status = setjmp(Env);
  if (status == 0)
  {
    printf("In status == 0 branch\n");
    longjmp(Env,1);
  }
  else
  {
    printf("In status != 0 branch\n");
  }
  return 0;
}

setjmp的初始调用返回0,因此采用第一个分支。对longjmp的调用将堆栈展开回到setjmp调用返回的点,但这次返回值为1(longjmp的第二个参数),所以第二个分支是拍摄。但是, status同时评估为0和非0的情况相同。

在实践中,它类似于写作

for (status = 0; status < 2; status++)
{
  if (status == 0)
    printf("In status == 0 branch\n");
  else
    printf("In status != 0 branch\n");
}

虽然语义不同。

你可能会在C ++中做类似丑陋的事情但有例外,但我不能说是C ++专家。

答案 9 :(得分:0)

对于单个陈述案例,只会执行其中一个,而不是两个。这是if的定义。

HOWEVER ,对于使用复合语句(aka语句块)的if语句,编译器可以优化代码以从then语句跳转到重复else块中的语句。

示例:

#include <iostream>
using namespace std;

int main(void)
{
  static const char common_text1[] = "Some common text here.\n";
  static const char common_text2[] = "Even more common code here.\n";
  if (true)
  {
     cout << "Condition is true.\n";
     cout << common_text1;  // Execution may jump to same line below.
     cout << common_text2;
  }
  else
  {
     cout << "\nCondition is false.\n";
     cout << common_text1;  // This line and the next may be executed when the
     cout << common_text2;  //   condition is true.
  }
  return 0;
}

在上面的示例中,编译器可以生成代码,以便在条件为true时,执行true块中的第一个语句,然后执行跳转到公共语句< / strong>在else区块中。

编译器正在重写代码:

  if (true)
  {
     cout << "Condition is true.\n";
  }
  else
  {
     cout << "\nCondition is false.\n";
  }

  // The compiler factored-out the common statements.
  cout << common_text1; 
  cout << common_text2;

当编译器在两个条件的语句块末尾附近看到重复语句时,可能会发生这种情况。

答案 10 :(得分:0)

switch ( x ) {
default: // if ( x )
  // stuff
  // no break
case 0: // else
  // more stuff
  break;
}

或更简单的

if ( x ) {
  // stuff
}
// more stuff

答案 11 :(得分:0)

您可以使用此:

#include <stdio.h> 
int main() 
{ 
if (//some condition//)
{ 
    IF:{
    printf("Hello "); //Code for if block.
     } 
    goto ELSE;
} 
else
{  
    goto IF;
    ELSE:{
      printf("world");//code for else block.
         }
}
return 0; 
} 

输出:Hello world

答案 12 :(得分:0)

除了 goto,您可以使用 ucontextsetjmp/longjump

  1. 您可以使用 ucontext 来切换执行流程。 例如:
#include <stdio.h>
#include <ucontext.h>

void func(void);

int  x = 0;
ucontext_t context, *cp = &context;

int main(void) {

  getcontext(cp);


  if (x == 0) {
    printf("hello\n");
    func();
  } else {
    printf("world\n");
  }

}

void func(void) {
  x++;
  setcontext(cp);
}

输出:

hello
world
  1. 您也可以使用 setjmp/longjmp
#include <stdio.h>
#include <setjmp.h>

int main()
{
    jmp_buf buf;

    if (setjmp(buf) != 0)
    {
        printf("world\n");
    }
    else
    {
        printf("hello\n");
        longjmp(buf, 0);
    }

    return 0;
}

输出:

hello
world

答案 13 :(得分:-1)

这是一个简单的例子:

#include <stdio.h>

int main() {
    int x;
    x = 6;
    if (x % 2 == 0) {
        printf("Divisible by two\n");
    }
    else if (x % 3 == 0) {
        printf("Divisible by three\n");
    }
    else {
        printf("Not divisible by two or three\n");
    }
    return 0;
}

打印

Divisible by two

不会

Divisible by two
Divisible by three