例如,这是一个或表达式:
c = f1 == 0 or f1 - f0 > th
Run Code Online (Sandbox Code Playgroud)
这是编译的C代码:
__pyx_t_24 = (__pyx_v_f1 == 0);
if (!__pyx_t_24) {
} else {
__pyx_t_23 = __pyx_t_24;
goto __pyx_L5_bool_binop_done;
}
__pyx_t_24 = ((__pyx_v_f1 - __pyx_v_f0) > __pyx_v_th);
__pyx_t_23 = __pyx_t_24;
__pyx_L5_bool_binop_done:;
__pyx_v_c = __pyx_t_23;
Run Code Online (Sandbox Code Playgroud)
为什么不输出这个?
__pyx_v_c = (__pyx_v_f1 == 0) || ((__pyx_v_f1 - __pyx_v_f0) > __pyx_v_th)
Run Code Online (Sandbox Code Playgroud)
是goto版本比||
?
使用以下两个文件:
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;
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
我必须分配f0
,f1
以及th
某些东西,以便编译器不会return 1
像C规范那样声明int
s被初始化0
并且f1 == 0
会产生true
,因此整个布尔语句将产生true
并且汇编将是:
main:
.LFB0:
.cfi_startproc
.L2:
movl $1, %eax
ret
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)
使用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
Run Code Online (Sandbox Code Playgroud)
因此,除非您禁用优化,否则其中的goto
指令将具有大约50%的指令,结果将是相同的.
输出C
代码丑陋的原因是因为解释器访问AST中的节点的方式.当or
被访问的节点,解释器首先计算第一参数,然后第二个.如果布尔表达式要复杂得多,则解析起来会容易得多.想象一下调用一个返回布尔值的lambda函数(我不确定Cython是否支持这个); 口译员必须遵循以下结构:
hold = ... evaluate the lambda expression...
if (hold) {
result = hold;
goto done; // short circuit
}
hold = ... evaluate the second boolean expression...
done:
...
Run Code Online (Sandbox Code Playgroud)
在解释阶段进行优化将是一项艰巨的任务,因此Cython甚至都不会打扰.