为什么GCC不会优化printf的调用? [英] Why doesn't GCC optimize this call to printf?

查看:262
本文介绍了为什么GCC不会优化printf的调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  #include< stdio.h> 
int main(void){
int i;
scanf(%d,& i);
if(i!= 30){return(0); }
printf(我等于%d \\\
,i);
}

看起来结果字符串总是我等于30 ,那么,为什么GCC不会调用printf来调用 puts() write(),例如?



(刚检查过生成的程序集,使用 gcc -O3 (版本5.3.1) ,或在 Godbolt编译器资源管理器

解决方案

首先,问题不在于如果;正如你所看到的, gcc 如果通过,如果并设法传递 30 直接到 printf



现在, gcc 确实有一些逻辑来处理 printf 的特殊情况(特别是,它优化了 printf(something \\\
甚至 printf(%s \ n,something) to puts(something)),但它非常具体,不会进一步发展;例如, printf(Hello%s \ n,world)保持原样。更糟糕的是,没有尾随的换行符的上述任何变体都不会被触及,即使它们可以转换为 fputs(something,stdout)

我想这可归结为两个主要问题:


  • 上述两种情况非常容易实施,并且发生频率很高,但对于其他情况来说,这很难实现;如果字符串不变并且性能很重要,程序员可以很轻松地处理它 - 实际上,如果 printf 的性能很关键,他不应该依赖于此



    如果你问我,即使只是 puts c>上面的优化已经为了风格点,你不会真的在任何人工测试用例上获得认真的性能。

  • 当你开始超越%s \ n printf 的领域是雷区,因为它具有强烈的依赖性在运行时环境中;特别是,许多的printf 说明符(不幸的是)的影响由区域设置,再加上有特定于实现的缺点和说明符(和 GCC <的卷扬机/ code>可以用的printf 从glibc的工作,MUSL,MinGW的/ MSVCRT,... - 在编译时你不能调用目标C运行时 - 认为当你是交叉编译的)。



    我同意这个简单的%d 情况可能是安全的,但我可以看看为什么他们可能决定避免过于聪明,只在这里执行最蠢和最安全的优化。 b

    对于好奇的读者,这里 a>是实际实现该优化的地方;你可以看到,该功能非常简单的情况下(和GIMPLE有限数量的匹配之外,因为并没有改变很多的这篇很好的文章概述了他们写的)。顺便说一句,源代码实际解释了为什么他们不能为非新行情况实现 fputs 变体(没有简单的方法来引用 stdout global在编译阶段)。


    #include <stdio.h>
    int main(void) { 
        int i;
        scanf("%d", &i);
        if(i != 30) { return(0); } 
        printf("i is equal to %d\n", i);
    }
    

    It appears that the resulting string will always be "i is equal to 30", so, why doesn't GCC optimize this call to printf with a call to puts(), or write(), for example?

    (Just checked the generated assembly, with gcc -O3 (version 5.3.1), or on the Godbolt Compiler Explorer)

    解决方案

    First of all, the problem is not the if; as you saw, gcc sees through the if and manages to pass 30 straight to printf.

    Now, gcc does have some logic to handle special cases of printf (in particular, it does optimize printf("something\n") and even printf("%s\n", "something") to puts("something")), but it is extremely specific and doesn't go much further; printf("Hello %s\n", "world"), for example, is left as-is. Even worse, any of the variants above without a trailing newline are left untouched, even if they could be transformed to fputs("something", stdout).

    I imagine that this comes down to two main problems:

    • the two cases above are extremely easy patterns to implement and happen quite frequently, but for the rest probably it's rarely worth the effort; if the string is constant and the performance is important, the programmer can take care of it easily - actually, if the performance of printf is critical he shouldn't be relying on this kind of optimization, which may break at the slightest change of format string.

      If you ask me, even just the puts optimizations above are already "going for the style points", you are not really going to gain serious performance in anything but artificial test cases.

    • When you start to go outside the realm of %s\n, printf is a minefield, because it has a strong dependency on the runtime environment; in particular, many printf specifiers are (unfortunately) affected by the locale, plus there are a hoist of implementation-specific quirks and specifiers (and gcc can work with printf from glibc, musl, mingw/msvcrt, ... - and at compile time you cannot invoke the target C runtime - think when you are cross-compiling).

      I agree that this simple %d case is probably safe, but I can see why they probably decided to avoid being overly smart and only perform the dumbest and safest optimizations here.


    For the curious reader, here is where this optimization is actually implemented; as you can see, the function matches a restricted number of very simple cases (and GIMPLE aside, hasn't changed a lot since this nice article outlining them was written). Incidentally, the source actually explains why they couldn't implement the fputs variant for the non-newline case (there's no easy way to reference the stdout global at that compilation stage).

    这篇关于为什么GCC不会优化printf的调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆