Одновременное выполнение блоков if и else - PullRequest
6 голосов
/ 13 июня 2010

В С или С ++

if ( x )
    statement1;
else
    statement2;

Для какого значения x будут выполняться оба оператора?

Я знаю, что мы можем выполнить if-else вместе вот так:

if(1){
    goto ELSE;
}
else{
    ELSE:
}

Есть ли способ, как значение? (Что, я думаю, невозможно. Спрашиваю, потому что кто-то спорит!)

Ответы [ 13 ]

24 голосов
/ 13 июня 2010

для какого значения 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".

15 голосов
/ 13 июня 2010

для какого значения x будут выполняться оба оператора?

Нет такого значения: либо значение оценивается как true (что-то! = 0), либо оно оцениваетсядо false) (0).Других возможных значений не существует.

Я знаю, что мы можем выполнить if-else вместе следующим образом: if (1) {goto ELSE;} else {ELSE:}

Это работает, но не зависит от значения условия if.

4 голосов
/ 13 июня 2010

Если вы не возражаете против некоторого неопределенного поведения, вы можете сделать это следующим образом в 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";
  }
}

Это прекрасно работает с GCC и Clang. Он работает, вызывая setjmp в буфере в b.j.b. Этот буфер хранится в классе, потому что он может быть массивом, а массивы могут быть скопированы, только если они заключены в класс. Затем конструктор backer принимает возвращаемое значение setjmp и инициализирует did. В деструкторе backer этот флаг проверяется, и если он равен false (первое возвращение setjmp), он возвращается назад и позволяет setjmp возвращать ненулевое значение. Деструктор backer вызывается, когда одна из веток заканчивается.

Компилятор может свободно копировать объект backer, созданный при инициализации b. Если это произойдет, конструктор копирования позаботится о том, чтобы установить did в true, гарантируя, что мы вернемся назад только один раз, даже если компилятор не оптимизировал копию backer во время инициализации.

Таким образом, программа печатает ab.

2 голосов
/ 13 июня 2010

Во-первых, это не глупый вопрос:)

Чтобы понять, почему вы не можете сделать это с помощью какого-то специального трюка, нам нужно перейти к сборке, которая генерируется оператором if (в частности, сборка для процессора Intel с gcc 4.2.1 - другая) архитектура приведет к разной сборке).

Возьмите эту простую программу на C:

#include <stdio.h>

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

Я собираюсь предположить, что у вас нет знаний о сборке - но не волнуйтесь, с этим примером не так уж сложно справиться. Здесь происходит то, что мы call scanf, и мы compare результат этого (i) с 8.

Далее, J UMP, если N OT E квалифицированная инструкция для метки L2. Это означает, что если i равно 8, выполняются следующие инструкции:

  • Переместить 3 в rbp
  • Переместить rbp в eax
  • Выйти (тем самым возвращая значение 3 из программы).

Однако, если i равно , а не равно 8, тогда, когда мы нажимаем на инструкцию jne, мы не прыгаем. Вместо этого мы:

  • Переместить 100 в rbp
  • J u mp безоговорочно на этикетку L4
  • Переместите rbp в eax и в итоге получите 100 из программы.

С созданной здесь сборкой, на самом деле есть только две возможные ветви. Вы не можете произвольно изменить порядок кода.

Так возможно ли выполнить обе ветви (когда они не являются return операторами)? Да, при условии, что ваш компилятор не способен правильно генерировать код ветвления. Но этого никогда не произойдет на компиляторе уровня производства.

2 голосов
/ 13 июня 2010

В рекурсивной функции могут выполняться обе ветви:

void recursive(bool first)
{
    if(first)
    {
        recursive(false);
    }
    else
    {
        //END
    }
}

Вызов с помощью

recursive(true)

выполнит ветвь if, за которой следует ветвь else

0 голосов
/ 09 февраля 2019

Вы можете использовать это:

#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; 
} 

Выход: Hello world

0 голосов
/ 13 июня 2010
switch ( x ) {
default: // if ( x )
  // stuff
  // no break
case 0: // else
  // more stuff
  break;
}

или намного проще

if ( x ) {
  // stuff
}
// more stuff
0 голосов
/ 13 июня 2010

Для случаев с одним оператором будет выполняться только один из них, а не оба.Это определение if.

HOWEVER , в случае оператора if с использованием составных операторов (он же блок операторов), компилятор может оптимизировать код для перехода из операторов then в дубликаты операторов вблок else.

Пример:

#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;
}

В вышеприведенном примере компилятор может сгенерировать код, чтобы при выполнении условия 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;

Это может происходить, когда компилятор видит дублирующиеся операторыближе к концу блока операторов для обоих условий.

0 голосов
/ 13 июня 2010

Не существует значения single для x, для которого будут выполняться все пути условного оператора (который является своего рода точкой условного оператора; вы хотитевыполнить одну ветку или другую на основе x).

Однако ...

В C (и C ++) вы можете использовать средство setjmp / longjmp для выполнения обоих путей 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;
}

Первоначальный вызов setjmp возвращает 0, поэтому берется первая ветвь.Вызов longjmp разматывает стек обратно до точки, в которой возвращается вызов setjmp, но на этот раз возвращаемое значение равно 1 (второй аргумент longjmp), поэтому берется вторая ветвь.Однако, это , а не - это то же самое, что status, оценивающее в 0 и не в 0 одновременно.

На практике это похоже на написание

for (status = 0; status < 2; status++)
{
  if (status == 0)
    printf("In status == 0 branch\n");
  else
    printf("In status != 0 branch\n");
}

, хотя семантика иная.

Возможно, вы могли бы сделать что-то похожее на C ++ с исключениями, но мне не хватает специалиста по C ++, чтобы сказать наверняка.

0 голосов
/ 13 июня 2010

Если это вопрос с подвохом, вы можете ответить с помощью

if( ({ statement2; 1; }) ) 
  statement1;
else
  statement2;

Используя выражения оператора GCC :) Для операторов выражения есть оператор запятой

if(expr2, 1) 
  expr1;
else
  expr2;

Это довольно популярный вопрос .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...