简体   繁体   English

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

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

Here is my test code: 这是我的测试代码:

#include<stdio.h>

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

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

I thought GCC should realize that a is a literal integer, and optimize to code like this: 我认为GCC应该意识到a是一个文字整数,并优化代码如下:

puts("1234");

But I got the following assembly code: 但是我得到了以下汇编代码:

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

There exists a lot of such code in my project, because I always believed that GCC would optimize for me, and even in some context where could simply use 'write()', I insisted using printf , because I thought I would gain benefit from its buffer mechanism. 在我的项目中存在很多这样的代码,因为我一直认为GCC会为我优化,甚至在某些可以简单地使用'write()'的上下文中,我坚持使用printf ,因为我认为我会从中受益它的缓冲机制。

Now I feel regret, for the overhead of paring a format string will kill any gain I have. 现在我感到遗憾,因为削减格式字符串的开销会杀死我的任何收益。 These codes in my project are quite low-level, and they might cause the performance bottleneck. 我项目中的这些代码非常低级,可能会导致性能瓶颈。

These codes in my project are quite low-level, and they might cause the performance bottleneck. 我项目中的这些代码非常低级,可能会导致性能瓶颈。

First off, I can assuage your fears that this is not possible. 首先,我可以减轻你的担心,这是不可能的。 The overhead of console I/O is tremendous (relatively speaking), so that will always be the bottleneck in your code, no matter what means you use to do it. 控制台I / O的开销是巨大的 (相对而言),因此无论您使用何种方式,它始终是代码中的瓶颈。

I thought gcc should realize that a is a literal integer, and optimize to code like this: 我认为gcc应该意识到a是一个文字整数,并优化代码如下:

 puts("1234"); 

Clearly it doesn't. 显然它没有。 GCC (and Clang) does perform an optimization where printf("...\\n"); GCC(和Clang) 确实printf("...\\n"); is transformed into puts("..."); 变成了puts("..."); , as you can see here , but this only happens when you use string literals with printf . ,正如你在这里看到的那样,但这只有在你使用printf 字符串文字时才会发生。 The optimizer doesn't (currently) peek into the format string, parse it, and optimize around it. 优化器(目前)不会查看格式字符串,解析它并围绕它进行优化。 You called printf , so you get printf . 你打电话给printf ,所以你得到printf

Compiler optimizations aren't guaranteed , so you shouldn't write code that relies on them without first verifying that the desired optimizations are in fact being applied under all circumstances in which you are interested (including code variations, compiler versions, target platforms, etc.). 无法保证编译器优化,因此如果没有首先验证所期望的优化实际上是在您感兴趣的所有情况下应用(包括代码变体,编译器版本,目标平台等),则不应编写依赖于它们的代码。 )。

If you'd like to suggest this as a possible improvement for the GCC optimizer, you can suggest an enhancement on their Bugzilla . 如果您想将此建议作为GCC优化器的可能改进,您可以建议对其Bugzilla进行增强。 But don't hold your breath on it being implemented any time soon. 但是,不要在适应的时候尽快屏住呼吸。 The logic required to implement this type of optimization is not really worth the effort, considering the real-world performance improvements that could be expected are minimal at best (see above). 实现这种类型的优化所需的逻辑并不值得付出努力,考虑到可以预期的实际性能改进最多是最小的(见上文)。

In the meantime, if you absolutely require this optimization with minimal changes to your code, then you can use some macro hackery : 与此同时,如果您绝对需要对代码进行最少的更改来进行此优化,那么您可以使用一些宏hackery

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

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

This does produce the desired output: 这确实产生了所需的输出:

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

A conforming library implementation could include functions beyond those defined by the Standard, which would change the way standard functions behave. 符合标准的库实现可以包括标准定义的函数,这将改变标准函数的行为方式。 For example, a library might include a __select_alternate_digits function that, when invoked, would cause succeeding calls to printf to display numbers using something other than the normal digits. 例如,库可能包含__select_alternate_digits函数,该函数在调用时会导致对printf后续调用使用除正常数字之外的其他内容来显示数字。

With such a library, given the code: 有了这样的库,给出了代码:

#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      
}

the call to __select_alternate_digits might cause the above program to output "¹²³" rather than "123". __select_alternate_digits的调用可能导致上述程序输出“123”而不是“123”。 If the compiler bundled its own printf function, it could know that its behavior wasn't going to be affected by any other function calls. 如果编译器捆绑了自己的printf函数,它可能知道它的行为不会受到任何其他函数调用的影响。 If it's using an outside library, however, then unless the program is completely free of any calls to functions the compiler knows nothing about, a quality compiler should assume those functions might have effects the compiler can't predict. 但是,如果它使用外部库,那么除非程序完全不需要编译器一无所知的函数调用,否则质量编译器应该假设这些函数可能具有编译器无法预测的效果。

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

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