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 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:
- Move 3 into
rbp
- Move
rbp
intoeax
- 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
J
ump
unconditionally to the label L4- Move
rbp
intoeax
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
.
- 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
- 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
精彩评论