编译器将 printf 更改为 put

2023-12-30

考虑以下代码:

#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(使用前将#替换为@)

编译器将 printf 更改为 put 的相关文章

随机推荐