同时执行if和else块
在C或C ++中
if ( x ) statement1; else statement2;
两个语句的执行值是什么?
我知道我们可以像这样一起执行if-else
:
if(1){ goto ELSE; } else{ ELSE: }
有什么办法,比如价值吗? (我认为这是不可能的。问,因为有人在争论!)
两个语句的值是什么?
没有这样的值:值的计算结果为true
(某些东西!= 0),或者计算结果为false
)(0)。 没有其他可能的值存在。
我知道我们可以像这样一起执行if-else:if(1){goto ELSE; } else {ELSE:}
这有效,但它根本不取决于if
条件的值。
对于什么值的x两个语句都将被执行?
仅在这种情况下(在类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”。
如果你不介意一些未定义的行为,你可以在C ++中这样做:
struct J { jmp_buf b; }; struct backer { backer(int v):did(v) { } backer(backer const& o):j(oj),did(o.did) { o.did = true; } ~backer() { if(!did) { longjmp(jb, 1); } } operator bool() { return !did; } J j; mutable bool did; }; int main() { if(backer b = setjmp(bjb)) { std::cout << "a"; } else { std::cout << "b"; } }
这适用于GCC和Clang。 它通过在bjb
的缓冲区上调用setjmp
来bjb
。 该缓冲区保存在一个类中,因为它可以是一个数组,只有将它们包装在一个类中才能复制数组。 然后, backer
的构造函数接受setjmp
的返回值并初始化它。 在backer
的析构函数中,该标志被测试,如果它是假的(第一次返回setjmp
),它会跳回并让setjmp
返回一个非零值。 当其中一个分支完成时,调用backer
的析构函数。
编译器可以自由复制在初始化b
构造的backer
对象。 如果发生这种情况,它的复制构造函数关心将did
设置为true
,确保我们只跳回一次,即使编译器在初始化期间没有优化backer
拷贝。
因此程序打印ab
。
在递归函数中,两个分支都可以执行:
void recursive(bool first) { if(first) { recursive(false); } else { //END } }
用它调用它
recursive(true)
将执行if分支,然后执行else分支
首先,这不是一个愚蠢的问题:)
要理解为什么不能通过任何特殊技巧实现这一目标,我们需要逐步调试由if语句生成的程序集(特别是具有gcc 4.2.1的Intel处理器的程序集 – 将导致不同的体系结构在不同的组装)。
采取这个简单的C程序:
#include 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
我会假设你不了解assembly – 但不要担心,这个例子并不十分难以跟上。 这里发生的是我们call scanf
,并将它的结果( i
)与8进行比较。
接下来,如果对标签L2的N
ot E
qual指令,则有一个J
ump。 这意味着如果i
等于8,则执行以下指令:
- 将3移动到
rbp
- 将
rbp
移动到eax
- 离开(从而从程序中返回值3)。
但是,如果i
不等于8,那么当我们点击jne
指令时,我们不会跳转。 相反,我们:
- 将100移动到
rbp
- 无条件地使用标签L4
- 将
rbp
移动到eax
并最终从程序返回100。
使用此处生成的程序集,实际上只有两个可能的分支。 您不能随意重新排序代码。
那么是否可以执行两个分支(当它们不是两个return
语句时)? 是的,条件是您的编译器无法正确生成分支代码。 但这在生产级编译器上永远不会发生。
没有狡猾的诡计,不,这是不可能的。 考虑表达式的含义:
if (cond) { ifTrue; } else { ifFalse; }
这表示如果cond
为真(非零值/ true
)则执行ifFalse
如果cond
为假(零/ false
)则执行ifFalse
。 由于cond
不能同时为true和false,因此如果没有特殊情况(例如goto
,则无法同时执行ifTrue
和ifFalse
。
您可以使用整数作为测试变量,并使用>,<,> =,<=,==检查其值
int x = 0; if ( x >= 0 ) { statement 1; } if ( x <= 0 ) { statement 2; }
在此示例中,仅当x为0时才执行这两个语句。否则只会执行其中一个语句。
如果这是一个技巧问题,你可以回答
if( ({ statement2; 1; }) ) statement1; else statement2;
使用GCC语句表达式:)对于表达式语句,有逗号运算符
if(expr2, 1) expr1; else expr2;
这是一个非常受欢迎的问题 。
对于x
,没有单个值可以执行条件语句的所有路径(这是条件语句的一种点 ;您希望基于x
执行一个分支或另一个分支)。
然而…
在C(和C ++)中,您可以使用setjmp
/ longjmp
工具来执行if
– else
两个路径:
#include #include 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
的第二个参数),因此采用第二个分支。 但是,这与同时评估为0和非0的status
。
在实践中,它与写作类似
for (status = 0; status < 2; status++) { if (status == 0) printf("In status == 0 branch\n"); else printf("In status != 0 branch\n"); }
虽然语义不同。
你可能会在C ++中做类似丑陋的事情但有例外,但我不能说是C ++专家。
对于单个语句情况,只会执行其中一个,而不是两者。 这是if
的定义。
但是 ,在使用复合语句(也就是语句块)的if
语句的情况下,编译器可以优化代码以从then
语句跳转到else
块中的重复语句。
例:
#include 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
块中的第一个语句,然后执行跳转到 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;
当编译器在语句块的末尾附近看到两个条件的重复语句时,可能会发生这种情况。
switch ( x ) { default: // if ( x ) // stuff // no break case 0: // else // more stuff break; }
或者更简单
if ( x ) { // stuff } // more stuff
这是一个简单的例子:
#include 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