没有变量的C函数调用是否在运行时预编译或计算?
基本上,如果我有代码:没有变量的C函数调用是否在运行时预编译或计算?,c,printf,conditional,C,Printf,Conditional,基本上,如果我有代码: void main(void){ foo(1,3); } 其中foo是: void foo(int x, int y){ if(x==0) return; else if (x==1){ if(y==0) printf("hello, world"); else if (y==2) printf("goodbye."); else if (y==3) printf("no."); else return;
void main(void){
foo(1,3);
}
其中foo是:
void foo(int x, int y){
if(x==0) return;
else if (x==1){
if(y==0) printf("hello, world");
else if (y==2) printf("goodbye.");
else if (y==3) printf("no.");
else return;
}
else return;
}
条件(假设它们适用)是在运行时计算的,还是本例中的“printf”语句只是在可执行文件中编译,基本上由编译器计算条件?编译器无法解释函数
foo()
中的代码。它将在函数体中生成if
s和printf()
s的代码
它没有做到这一点有几个原因。其中之一是功能的链接。它没有声明为静态
,这意味着它可以在其他.c
文件中使用;编译器不能仅仅猜测实际调用中参数的值
使用不同的参数调用它以输出不同的内容,这就是您首先编写函数的原因
根据调用时使用的编译器和优化开关,它可以内联调用foo(1,3)
。内联意味着编译器用函数体的代码替换对函数的调用。在这种情况下,它可以优化内联代码,因为它知道参数的值,并且可以判断哪个printf()
运行;它删除if
s和另一个printf()
s,因为它们是死代码,而不是调用foo(1,3)
它生成printf(“no.”)的代码代码>。但这只能是因为函数调用的参数是常量(即,它们在编译时是已知的)
然而,即使在这种情况下,仍然会生成函数的代码。
如果调用foo(1,3)
是对函数的唯一一个调用,并且编译器能够内联它,当链接器生成最终可执行文件时,该函数的代码将被删除(将被忽略,因为它未被调用)
检查编译器的命令行开关以获取优化标志。还要检查如何指示它生成一个程序集文件(带注释),以查看它生成了什么代码(您可以在那里看到它是否内联了对foo(1,3)
的调用)。反汇编后,foo函数如下所示:
011714AE push 3
011714B0 push 1
011714B2 call foo (11711D6h)
这意味着C函数首先将变量推入内存,然后从esp返回以在运行时进行求值
条件(假设它们适用)是否会在运行时进行计算,
或者本例中的“printf”语句只是在
可执行文件,基本上由编译器计算条件
只要语义保持所需的相同,编译器就可以自由地发出它想要的任何代码。大多数编译器都有可配置的优化级别,可以控制它们在转换源代码时的积极程度。如果是gcc
,则相关标志为-O
x
查看发出了什么代码的唯一方法是亲自检查它。在gcc
的情况下,您可以使用输出生成的汇编程序的-S
标志
在您的程序中,gcc-O0-S opt.c
(无优化)产生以下结果:
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $3, %esi
movl $1, %edi
call foo # <---
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
void main(void)
是错误的,它是int main(void)
如果您的编译器没有告诉您它是错误的,那么您可能需要配置编译器警告或更改编译器。这显然是一个小问题,我在问,因为我正在处理一个实时性能优先的嵌入式系统,这取决于编译器,编译器设置,可能是两个函数是否在同一个编译单元中(或者如果您有PGO)。。。C标准允许编译器进行优化,但本质上没有一个是强制性的。如果你让编译器优化代码,那么它将得到优化,但无论如何你应该使用开关
,不是吗?@iharob,因为我的评论没有回复你:对于这个应用程序,代码运行在带有JeOS的嵌入式系统上,我不在乎main是否/何时返回,如果返回又会是什么,因为我的代码将始终从“main()”的顶部重新开始运行。这肯定是特定于实现的,取决于编译器、操作系统、优化标志。原因取决于编译器,但我确信所有编译器的操作都会给出相同的结果。如果您不更改代码,它将在运行时进行计算。
.LC2:
.string "no."
(...)
main:
.LFB12:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $.LC2, %edi
movl $0, %eax
call printf # <----
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc