В C или C++
if ( x )
statement1;
else
statement2;
Поскольку, что значение x
оба оператора будут выполняться?
Я знаю, что мы можем выполниться if-else
вместе как это:
if(1){
goto ELSE;
}
else{
ELSE:
}
Есть ли какой-либо путь, как значение? (Который я думаю, не возможно. Выяснение, потому что кто-то спорит!)
для какого значения x будут выполняться оба оператора?
Такого значения нет: либо значение оценивается как true
(что-то! = 0 ), или он оценивается как ложь
) (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".
Вы можете использовать целое число в качестве тестовой переменной и проверять его значение с помощью>, <,> =, <=, ==
int x = 0;
if ( x >= 0 ) {
statement 1;
}
if ( x <= 0 ) {
statement 2;
}
В этом примере оба оператора выполняются, только если x равен 0. Иначе будет только один из них.
Не существует единственного значения для 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
) , поэтому берется вторая ветвь. Однако это не то же самое, что статус
, оцениваемый одновременно как 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 ++, чтобы сказать наверняка.
Нет, без хитрых уловок это невозможно. Подумайте, что означает выражение:
if (cond) {
ifTrue;
} else {
ifFalse;
}
Здесь говорится, что нужно выполнить ifTrue
, если cond
истинно (ненулевое значение / true
), и выполнить ifFalse
if cond
ложно (ноль / ложь
). Поскольку cond
не может быть одновременно истинным и ложным, вы не можете выполнить оба ifTrue
и ifFalse
без особого случая, например goto
.
Вот простой пример:
#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;
}
Печать
Divisible by two
НЕ
Divisible by two
Divisible by three
В рекурсивной функции могут выполняться обе ветви:
void recursive(bool first)
{
if(first)
{
recursive(false);
}
else
{
//END
}
}
Вызов ее с помощью
recursive(true)
выполнит ветвь if, за которой следует ветвь else
Если это вопрос с подвохом, вы можете ответить с помощью
if( ({ statement2; 1; }) )
statement1;
else
statement2;
Использование выражений операторов GCC :) Для операторов выражений есть оператор запятой
if(expr2, 1)
expr1;
else
expr2;
. Это довольно популярный вопрос .
Для случаев с одним оператором будет выполняться только один из них, а не оба. Это определение , если
.
ОДНАКО , в случае оператора 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;
}
В приведенном выше примере компилятор может сгенерировать код так, чтобы при условии истина
выполнялась первая инструкция в блоке истина
, затем выполнение переходит к общим операторам в блоке 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
Если вы не возражаете против неопределенного поведения, вы можете сделать это в 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
этот флаг проверяется, и если он ложный (первый возврат setjmp
), он возвращается назад и позволяет setjmp
вернуть ненулевое значение. . Деструктор backer
вызывается, когда заканчивается одна из ветвей.
Компилятор может скопировать объект backer
, созданный при инициализации b
. Если это произойдет, его конструктор копирования позаботится о настройке did
на true
, гарантируя, что мы вернемся назад только один раз, даже если компилятор не оптимизировал поддержку .
копировать во время инициализации.
Таким образом, программа печатает ab
.
Во-первых, это не глупый вопрос :)
Чтобы понять, почему вы не можете сделать это с помощью особых ухищрений, нам нужно сделать шаг вниз к сборке, которая генерируется 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
Я собираюсь предположить, что вы не знаете ассемблера - но не волнуйтесь, этот пример не так уж сложен для понимания. Здесь происходит следующее: мы вызываем scanf
, и сравниваем
результат (i
) с 8.
Далее происходит J
ump if N
ot E
qual инструкция к метке L2. Это означает, что если i
равно 8, то выполняются следующие инструкции:
rbp
rbp
into eax
Однако, если i
не равно 8, то при выполнении инструкции jne
мы не переходим. Вместо этого мы:
rbp
J
ump
безусловно на метку L4rbp
в eax
и в итоге возвращаем 100 из программы. В ассемблере, сгенерированном здесь, есть только два возможных ответвления. Вы не можете произвольно переупорядочить код.
Так можно ли выполнить обе ветви (когда они не являются операторами return
)? Да, при условии, что ваш компилятор не способен корректно создавать ветвящийся код. Но это никогда не произойдет на компиляторе производственного уровня.