没有变量的 C 函数调用是否在 运行 时预编译或求值?
Are C function calls without variables precompiled or evaluated at run time?
基本上,如果我有代码:
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 的代码生成到函数的主体中。
它不这样做有几个原因。其中之一就是功能的联动。它没有声明为 static
,这意味着它可以在其他 .c
文件中使用;编译器不能仅仅猜测其在实际调用中的参数值是什么。
用不同的参数调用它以输出不同的东西是您首先编写该函数的原因。
根据您调用它时使用的编译器和优化开关,它可以内联对 foo(1,3)
的调用。内联意味着编译器用函数体的代码替换对函数的调用。在这种情况下,它可以优化内联代码,因为它知道参数的值并且可以判断哪个 printf()
运行;它删除了 if
和其他 printf()
,因为它们是死代码,而不是调用 foo(1,3)
,它生成 printf("no.");
的代码。但这只会发生,因为你的函数调用的参数是常量(即它们在编译时已知)。
但是,即使在这种情况下,函数的代码仍然会生成。
如果调用 foo(1,3);
是对该函数的唯一调用并且编译器能够内联它,则链接器将删除该函数的代码(将被忽略,因为它未被调用),当它生成最终可执行文件。
检查编译器的命令行开关以获取优化标志。还要检查如何指示它生成程序集文件(带注释)以查看它生成的代码(您可以在那里看到它是否内联对 foo(1,3)
的调用)。
像这样反汇编 foo 函数后:
011714AE push 3
011714B0 push 1
011714B2 call foo (11711D6h)
这意味着 C 函数首先将变量压入内存,然后在 运行 时间
从 esp 返回以进行评估
Will the conditionals (assuming they apply) be evaluated at run time,
or will the 'printf' statements in this case simply compile in the
executable, essentially with the compiler evaluating the conditionals?
只要语义保持不变,编译器就可以自由地发出它想要的任何代码需要引用。大多数编译器都有可配置的优化级别,可以控制它们在转换源代码时的激进程度。在 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 , %esi
movl , %edi
call foo # <---
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
而 gcc -O1 -S opt.c
和更高的优化级别导致:
.LC2:
.string "no."
(...)
main:
.LFB12:
.cfi_startproc
subq , %rsp
.cfi_def_cfa_offset 16
movl $.LC2, %edi
movl [=11=], %eax
call printf # <----
addq , %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
基本上,如果我有代码:
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 的代码生成到函数的主体中。
它不这样做有几个原因。其中之一就是功能的联动。它没有声明为 static
,这意味着它可以在其他 .c
文件中使用;编译器不能仅仅猜测其在实际调用中的参数值是什么。
用不同的参数调用它以输出不同的东西是您首先编写该函数的原因。
根据您调用它时使用的编译器和优化开关,它可以内联对 foo(1,3)
的调用。内联意味着编译器用函数体的代码替换对函数的调用。在这种情况下,它可以优化内联代码,因为它知道参数的值并且可以判断哪个 printf()
运行;它删除了 if
和其他 printf()
,因为它们是死代码,而不是调用 foo(1,3)
,它生成 printf("no.");
的代码。但这只会发生,因为你的函数调用的参数是常量(即它们在编译时已知)。
但是,即使在这种情况下,函数的代码仍然会生成。
如果调用 foo(1,3);
是对该函数的唯一调用并且编译器能够内联它,则链接器将删除该函数的代码(将被忽略,因为它未被调用),当它生成最终可执行文件。
检查编译器的命令行开关以获取优化标志。还要检查如何指示它生成程序集文件(带注释)以查看它生成的代码(您可以在那里看到它是否内联对 foo(1,3)
的调用)。
像这样反汇编 foo 函数后:
011714AE push 3
011714B0 push 1
011714B2 call foo (11711D6h)
这意味着 C 函数首先将变量压入内存,然后在 运行 时间
从 esp 返回以进行评估Will the conditionals (assuming they apply) be evaluated at run time, or will the 'printf' statements in this case simply compile in the executable, essentially with the compiler evaluating the conditionals?
只要语义保持不变,编译器就可以自由地发出它想要的任何代码需要引用。大多数编译器都有可配置的优化级别,可以控制它们在转换源代码时的激进程度。在 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 , %esi
movl , %edi
call foo # <---
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
而 gcc -O1 -S opt.c
和更高的优化级别导致:
.LC2:
.string "no."
(...)
main:
.LFB12:
.cfi_startproc
subq , %rsp
.cfi_def_cfa_offset 16
movl $.LC2, %edi
movl [=11=], %eax
call printf # <----
addq , %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc