c - 为什么 GCC 没有将这个 'printf' 优化为 'puts' ?

标签 c gcc assembly compiler-optimization

这是我的测试代码:

#include<stdio.h>

static inline void foo(int a){
    printf("%x\n", a);  
}

int main(void){
    foo(0x1234);    
    return 0;
}

我认为 GCC 应该意识到 a 是一个文字整数,并优化为这样的代码:

puts("1234");

但是我得到了如下的汇编代码:

│0x8048341 <main+17>     push   $0x1234                                        
│0x8048346 <main+22>     push   $0x80484e0                                  
│0x804834b <main+27>     push   $0x1                                        
│0x804834d <main+29>     call   0x8048310 <__printf_chk@plt> 

在我的项目中有很多这样的代码,因为我一直相信GCC会为我优化,甚至在一些可以简单地使用'write()'的上下文中,我坚持使用printf,因为我认为我会从它的缓冲机制中获益。

现在我感到很遗憾,因为削减格式字符串的开销会扼杀我的任何收获。我项目中的这些代码非常底层,它们可能会导致性能瓶颈。

最佳答案

These codes in my project are quite low-level, and they might cause the performance bottleneck.

首先,我可以消除您对这不可能的恐惧。控制台 I/O 的开销是巨大的(相对而言),因此无论您使用什么方式,这始终是您代码中的瓶颈。

I thought gcc should realize that a is a literal integer, and optimize to code like this:

puts("1234");

显然不是。 GCC(和 Clang)does perform an optimization where printf("...\n"); is transformed into puts("..."); ,如您所见here ,但这只会在您将 string literalsprintf 一起使用时发生。优化器(当前)不会查看格式字符串、解析它并围绕它进行优化。你调用了 printf,所以你得到了 printf

编译器优化不是保证,因此您不应该编写依赖的代码,而不首先验证所需的优化实际上在所有情况下都得到应用您感兴趣的内容(包括代码变体、编译器版本、目标平台等)。

如果您想建议这是对 GCC 优化器的可能改进,您可以在 their Bugzilla 上提出增强建议.但是不要对它很快就会实现抱有希望。考虑到现实世界中预期的性能改进充其量是最小的(见上文),实现此类优化所需的逻辑并不值得付出努力。

与此同时,如果您绝对需要对代码进行最少更改的这种优化,那么您可以使用 some macro hackery :

#define STRINGIFY_INTERNAL(x)  #x
#define STRINGIFY(x)           STRINGIFY_INTERNAL(x)

#define foo(a)                 puts(STRINGIFY(a))

这确实会产生所需的输出:

.LC0:
        .string "0x1234"
MyFunction:
        sub     esp, 24
        push    OFFSET FLAT:.LC0
        call    puts
        xor     eax, eax
        add     esp, 28
        ret

关于c - 为什么 GCC 没有将这个 'printf' 优化为 'puts' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44406798/

相关文章:

c - 蜂鸣命令正在破坏我的功能

c++ - 微软C++编译器太烦人了!是否有针对 Windows 32/64 位编译的替代方法?

linux - 将 .text 部分放在 ELF 的最后

c - 混合 c 和汇编 (ARM) 子程序

assembly - 在子例程中使用 TRAP 例程? - LC3总成

C字大小和标准大小

c语言作业与incr/decr运算符

c - 在 x86 汇编中,为什么读取标准输入会阻塞程序?

python - 在 python 中嵌入 C

exception - 可移植地处理 C++ 中的异常错误