繁体   English   中英

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

[英]Why didn't GCC optimize this 'printf' to 'puts'?

这是我的测试代码:

#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 ,因为我认为我会从中受益它的缓冲机制。

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

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

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

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

 puts("1234"); 

显然它没有。 GCC(和Clang) 确实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))

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

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

符合标准的库实现可以包括标准定义的函数,这将改变标准函数的行为方式。 例如,库可能包含__select_alternate_digits函数,该函数在调用时会导致对printf后续调用使用除正常数字之外的其他内容来显示数字。

有了这样的库,给出了代码:

#include <stdio.h> // Could legitimately include functions that aren't
                  // defined by the Standard, but which start with __.

int main(void)
{
  __select_alternate_digits("⁰¹²³⁴⁵⁶⁷⁸⁹");
  printf("%d",123);
  __select_alternate_digits(0); // Reset to default set      
}

__select_alternate_digits的调用可能导致上述程序输出“123”而不是“123”。 如果编译器捆绑了自己的printf函数,它可能知道它的行为不会受到任何其他函数调用的影响。 但是,如果它使用外部库,那么除非程序完全不需要编译器一无所知的函数调用,否则质量编译器应该假设这些函数可能具有编译器无法预测的效果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM