Simultaneous execution of both if and else blocks

后端 未结 13 2300
难免孤独
难免孤独 2020-12-10 17:45

In C or C++

if ( x )
    statement1;
else
    statement2;

For what value of x will both statements be executed?

I know

相关标签:
13条回答
  • 2020-12-10 18:03

    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.

    0 讨论(0)
  • 2020-12-10 18:05

    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 讨论(0)
  • 2020-12-10 18:06

    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.

    0 讨论(0)
  • 2020-12-10 18:07
    switch ( x ) {
    default: // if ( x )
      // stuff
      // no break
    case 0: // else
      // more stuff
      break;
    }
    

    or the much simpler

    if ( x ) {
      // stuff
    }
    // more stuff
    
    0 讨论(0)
  • 2020-12-10 18:09

    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.

    0 讨论(0)
  • 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.

    0 讨论(0)
提交回复
热议问题