考虑以下代码:
#include <stdio.h>
void foo() {
printf("Hello world\n");
}
void bar() {
printf("Hello world");
}
这两个函数生成的程序集是:
.LC0:
.string "Hello world"
foo():
mov edi, OFFSET FLAT:.LC0
jmp puts
bar():
mov edi, OFFSET FLAT:.LC0
xor eax, eax
jmp printf
现在我知道了之间的区别put 和 printf https://stackoverflow.com/questions/2454474/what-is-the-difference-between-printf-and-puts-in-c,但我发现这很有趣,gcc 能够内省 const char* 并确定是否调用 printf 或 puts。
另一个有趣的事情是,在bar
,编译器将返回寄存器清零(eax
)尽管它是一个void
功能。为什么它在那里而不是在里面这样做foo
?
我假设编译器“内省我的字符串”是否正确,或者对此有其他解释?
我假设编译器“内省我的字符串”是否正确,或者对此有其他解释?
是的,这正是发生的情况。这是编译器完成的非常简单且常见的优化。
自从你第一次printf()
调用只是:
printf("Hello world\n");
它相当于:
puts("Hello world");
Since puts()
不需要扫描和解析字符串的格式说明符,它比printf()
。编译器注意到您的字符串以换行符结尾并且不包含格式说明符,因此会自动转换调用。
这也节省了一点空间,因为现在只有一个字符串"Hello world"
需要存储在生成的二进制文件中。
请注意,对于以下形式的调用,这通常是不可能的:
printf(some_var);
If some_var
不是一个简单的常量字符串,编译器无法知道它是否以\n
.
其他常见的优化有:
-
strlen("constant string")
可能会在编译时进行评估并转换为数字。
-
memmove(location1, location2, sz)
可能会转变为memcpy()
如果编译器确定location1
and location2
不要重叠。
-
memcpy()
小尺寸可以在一个单一的mov
指令,即使大小较大,有时也可以内联调用以加快速度。
另一个有趣的事情是,在bar
,编译器将返回寄存器清零(eax
)尽管它是一个void
功能。为什么它在那里而不是在里面这样做foo
?
看这里:为什么 %eax 在调用 printf 之前被清零? https://stackoverflow.com/questions/6212665/why-is-eax-zeroed-before-a-call-to-printf
相关有趣的帖子
- 为什么 GCC 不优化对 printf 的调用? https://stackoverflow.com/q/37435984
- C 程序中 printf 可以自动替换为 put 吗? https://stackoverflow.com/q/25816659
- 为什么无论我使用printf还是puts,当我反汇编时它都会显示puts? https://stackoverflow.com/q/41371002
- printf@plt 和 puts@plt 之间的区别 https://stackoverflow.com/q/39007002
- -O2 将 printf("%s\n", str) 优化为 put(str) https://stackoverflow.com/q/36343733
- 如何让 GCC 编译器不优化“printf”等标准库函数调用? https://stackoverflow.com/questions/57062430/how-can-i-get-the-gcc-compiler-to-not-optimize-a-standard-library-function-call
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)