Используя следующие два файла:
test.c
:
int main(int argc, char** argv) {
int c, f0, f1, th;
int hold, hold1;
f0 = (int) argv[1];
f1 = (int) argv[2];
th = (int) argv[3];
hold1 = (f0 == 0);
if (!hold1) {
} else {
hold = hold1;
goto done;
}
hold1 = (f1 - f0 > th);
hold = hold1;
done: c = hold;
return c;
}
test2.c
:
int main(int argc, char** argv) {
int c, f0, f1, th;
f0 = (int) argv[1];
f1 = (int) argv[2];
th = (int) argv[3];
c = (f1 == 0) || (f1 - f0 > th);
return c;
}
я должен был назначить f0
, f1
и th
к чему-то, так что компилятор будет не просто return 1
, как указано в спецификации C, int
s инициализируются 0
и f1 == 0
даст true
, и, таким образом, весь логический оператор даст true
и сборка будет:
main:
.LFB0:
.cfi_startproc
.L2:
movl $1, %eax
ret
.cfi_endproc
Компиляция с использованием GCC
с -S -O2
флаги (оптимизация включена), как test.s
и test2.s
стать :
main:
.LFB0:
.cfi_startproc
movl 8(%rsi), %edx
movq 16(%rsi), %rdi
movl $1, %eax
movq 24(%rsi), %rcx
testl %edx, %edx
je .L2
subl %edx, %edi
xorl %eax, %eax
cmpl %ecx, %edi
setg %al
.L2:
rep
ret
.cfi_endproc
Так что, если вы не отключить оптимизацию, в котором один с goto
будет иметь около 50% больше инструкций, то Ресул t будет одинаковым.
Причина, по которой вывод C
является уродливым, объясняется тем, как интерпретатор посещает узлы в AST. При посещении узла or
интерпретатор сначала оценивает первый параметр, а затем второй. Если бы логическое выражение было намного сложнее, было бы намного легче разобрать. Представьте, что вы вызываете функцию лямбда, которая возвращает логическое значение (я не уверен, поддерживает ли Cython это); интерпретатор должен следовать структуру:
hold = ... evaluate the lambda expression...
if (hold) {
result = hold;
goto done; // short circuit
}
hold = ... evaluate the second boolean expression...
done:
...
Это будет непростой задачей для оптимизации во время интерпретации фазы и, таким образом, Cython даже не заморачиваться.
Похоже 'goto' является частью короткого замыкания' or'. – hpaulj