为什么GCC没有将'printf'优化为'put'?

wei*_*huo 2 c assembly gcc compiler-optimization

这是我的测试代码:

#include<stdio.h>

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

int main(void){
    foo(0x1234);    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

puts("1234");
Run Code Online (Sandbox Code Playgroud)

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

?0x8048341 <main+17>     push   $0x1234                                        
?0x8048346 <main+22>     push   $0x80484e0                                  
?0x804834b <main+27>     push   $0x1                                        
?0x804834d <main+29>     call   0x8048310 <__printf_chk@plt> 
Run Code Online (Sandbox Code Playgroud)

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

现在我感到遗憾,因为削减格式字符串的开销将会扼杀任何我获得的收益.我项目中的这些代码非常低级,可能会导致性能瓶颈.

Cod*_*ray 6

我项目中的这些代码非常低级,可能会导致性能瓶颈.

首先,我可以减轻你的担心,这是不可能的.控制台I/O的开销是巨大的(相对而言),因此无论您使用何种方式,它始终是代码中的瓶颈.

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

puts("1234");
Run Code Online (Sandbox Code Playgroud)

显然它没有.GCC(以及锵)执行其中的优化printf("...\n");转化为puts("...");,你可以看到这里,但是当你用这只是发生字符串文字printf.优化器(目前)不会查看格式字符串,解析它并围绕它进行优化.你打来电话printf,所以你得到了printf.

无法保证编译器优化,因此如果没有首先验证所期望的优化实际上是在您感兴趣的所有情况下应用(包括代码变体,编译器版本,目标平台等),则不应编写依赖于它们的代码. ).

如果您想将此建议作为GCC优化器的可能改进,您可以建议对其Bugzilla进行增强.但是,不要在适应的时候尽快屏住呼吸.实现这种类型的优化所需的逻辑并不值得付出努力,考虑到可以预期的实际性能改进最多是最小的(见上文).

与此同时,如果您绝对需要对代码进行最少的更改来进行此优化,那么您可以使用一些宏hackery:

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

#define foo(a)                 puts(STRINGIFY(a))
Run Code Online (Sandbox Code Playgroud)

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

.LC0:
        .string "0x1234"
MyFunction:
        sub     esp, 24
        push    OFFSET FLAT:.LC0
        call    puts
        xor     eax, eax
        add     esp, 28
        ret
Run Code Online (Sandbox Code Playgroud)