开发者

Simultaneous execution of both if and else blocks

In C or C++

if ( x )
    statement1;
else
    statement2;

For what value of x will both statements be executed?

I know we can execute if-else together like this:

if(1){
    goto ELSE;
}
e开发者_运维知识库lse{
    ELSE:
}

Is there any way, like a value? (Which I think is not possible. Asking because someone is arguing!)


for what value of x both statements will be executed??

Only in this case (on unix-like systems):

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

In this case both branches will be always called simultaineously (well, more or less simultaneously), but in different processes.

I know we can execute if-else together like this:

This:

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

is a wrong construct. You need to use something like this instead:

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

If one branch is always called, then you don't need "else".


for what value of x both statements will be executed?

There is no such value: either the value evaluates to true (something != 0), or it evaluates to false) (0). No other possible values exist.

I know we can execute if-else together like this: if(1){ goto ELSE; } else{ ELSE: }

That works but it isn’t depending of the value of the if condition at all.


If you don't mind some undefined behavior, you can do it like this in 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";
  }
}

This works fine with GCC and Clang. It works by calling setjmp on the buffer in b.j.b. That buffer is kept wrapped in a class because it can be an array, and arrays can only be copied if they are wrapped in a class. backer's constructor then takes setjmp's return value and initializes did with it. In backer's destructor that flag is tested and if it's false (first return of setjmp), it jumps back and let setjmp return a non-zero value. The destructor of backer is called when one of the branches finish.

The compiler is free to copy the backer object constructed in initializing b. If that happens, the copy constructor of it cares about setting did to true, ensuring that we jump back only one time even if the compiler didn't optimize out the backer copy during initialization.

Thus the program prints ab.


In a recursive function both branches can be executed:

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

Invoking it with

recursive(true)

will execute the if branch followed by the else branch


First off, this isn't a stupid question :)

To understand why you can't accomplish this with any special trickery, we need to step down to the assembly that gets generated by an if-statement (particularly, the assembly for an Intel processor with gcc 4.2.1 -- different architectures will result in different assembly).

Take this simple C program:

#include <stdio.h>

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

If the user enters a non-zero integer, we return 100; otherwise we return 3. The actual condition doesn't really matter here, because we're only interested in the assembly generated for 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

I'm going to assume you have no knowledge of assembly -- but don't worry, this example isn't terribly hard to keep up with. What's happening here is that we call scanf, and we compare the result of it (i) with 8.

Next, there's a Jump if Not Equal instruction to the label L2. This means that if i is equal to 8, the following instructions executed are:

  • Move 3 into rbp
  • Move rbp into eax
  • Leave (thereby returning the value 3 from the program).

However, if i is not equal to 8, then when we hit the jne instruction, we don't jump. Instead, we:

  • Move 100 into rbp
  • Jump unconditionally to the label L4
  • Move rbp into eax and end up returning 100 from the program.

With the assembly generated here, there are really only two possible branches. You can't arbitrarily reorder the code.

So would it be possible to execute both branches (when they aren't both return statements)? Yes, on the condition that your compiler is incapable of correctly producing branching code. But that would never happen on a production-level compiler.


Without devious trickery, no, this is not possible. Consider what the expression means:

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

This says to execute ifTrue if cond is true (a non-zero value/true), and to execute ifFalse if cond is false (zero/false). Since cond can't be simultaneously true and false, you can't execute both ifTrue and ifFalse without a special case, such as goto.


You can use an integer as test variable and check its value using >,<,>=,<=,==

    int x = 0;

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

In this example, both statements are only executed if x is 0. Otherwise only one of them will be.


If it is a trick question, you could answer with

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

Using GCC statement expressions :) For expression statements, there is the comma operator

if(expr2, 1) 
  expr1;
else
  expr2;

This is a quite popular question.


There is no single value for x for which all paths of a conditional statement will be executed (which is kind of the point of a conditional statement; you want to execute one branch or the other based on x).

However...

In C (and C++), you could use the setjmp/longjmp facility to execute both paths of an 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;
}

The initial call to setjmp returns 0, so the first branch is taken. The call to longjmp unwinds the stack back to the point where the setjmp call returns, but this time the return value is 1 (the second argument to longjmp), so the second branch is taken. However, this is not the same thing as status evaluating to 0 and non-0 simultaneously.

In practice, it's similar to writing

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

although the semantics are different.

You could probably do something similarly ugly in C++ with exceptions, but I'm not enough of a C++ expert to say for sure.


For single statement cases, only one of them will be executed, not both. This is the definition of if.

HOWEVER, in the case of an if statement using compound statements (a.k.a. statement block), the compiler may optimize the code to jump from the then statements into duplicate statements in the else block.

Example:

#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;
}

In the above example, the compiler may generate code so that when the condition is true, the first statement in the true block is executed, then execution jumps to the common statements in the else block.

The compiler is rewriting the code:

  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;

This may happen when the compiler sees duplicate statements near the end of the statement block for both conditions.


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

or the much simpler

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


You can use this:

#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; 
} 

Output: Hello world


except goto you can use ucontext or setjmp/longjump.

  1. you can use ucontext to switch the execute flow. for example:
#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);
}

output:

hello
world
  1. you can also use 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;
}

output:

hello
world


Here's a simple example:

#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;
}

Prints

Divisible by two

NOT

Divisible by two
Divisible by three
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜