同时执行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的缓冲区上调用setjmpbjb 。 该缓冲区保存在一个类中,因为它可以是一个数组,只有将它们包装在一个类中才能复制数组。 然后, 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 ,则无法同时执行ifTrueifFalse

您可以使用整数作为测试变量,并使用>,<,> =,<=,==检查其值

  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工具来执行ifelse两个路径:

 #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