In C or C++
if ( x )
statement1;
else
statement2;
For what value of x
will both statements be executed?
I know
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.
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
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 J
ump if N
ot E
qual instruction to the label L2. This means that if i
is equal to 8, the following instructions executed are:
rbp
rbp
into eax
However, if i
is not equal to 8, then when we hit the jne
instruction, we don't jump. Instead, we:
rbp
J
ump
unconditionally to the label L4rbp
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.
switch ( x ) {
default: // if ( x )
// stuff
// no break
case 0: // else
// more stuff
break;
}
or the much simpler
if ( x ) {
// stuff
}
// more stuff
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
.
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.