• gcc 中 O选项对空函数的优化


    将空函数优化掉是一项很有意义的工作。比如,在程序中,常常要定义一个打印函数。如果在 release时,把这个函数使用条件编译定义为空函数。

    且此空函数被优化掉,那就可以极大地提高程序的性能。

    测试表明: 在gcc中,使用 -O可以优化掉内联的空函数。默认情况下,空函数不会被优化掉。即使使用 -O,也不会优化掉非内联的空函数。

    内联的空函数会被优化掉是很容易理解的。函数被内联后,没有了参数入栈出栈操作,自然也就无代码可生成了。

    但没有优化选项是,内联函数不会被优化,我却想不通。既然 声明为 inlinne,为什么函数没有被优化掉。那还要 inline何用?

    下面分别是c源文件, 未优化的汇编代码,优化后的汇编代码。

    // source code empty.c


    inline void dbg( const char* s )
    {
    };
    int main()
    {
    for( int i = 0; i < 10 ; i ++ )
    {
    dbg( "hello!" );
    }
    return 0;
    }

    /* assembler code generated by gcc 3.2.3 on redhat platform
    env: GCC: (GNU) 3.2.3 20030502 (Red Hat Linux 3.2.3-47.3)
    cmd: $ gcc -S -masm=intel -O emptyfun.c -o noopt.asm

    */


    main:
    push %ebp
    mov %ebp, %esp
    sub %esp, 8
    and %esp, -16
    mov %eax, 0
    sub %esp, %eax
    mov DWORD PTR [%ebp-4], 0 ;
    .L3: ; for( ; ; ; )
    cmp DWORD PTR [%ebp-4], 9 ; if ( i > 9 )
    jle .L6 ; {
    jmp .L4 ; break;
    .L6: }
    sub %esp, 12 ; //为 dbg()分配栈空间
    push OFFSET FLAT:.LC0 ; //参数 "hello!" 压栈
    call dbg ; dbg( "hello!" );
    add %esp, 16 ; // 平栈
    lea %eax, [%ebp-4]
    inc DWORD PTR [%eax] ; i++;
    jmp .L3
    .L4:
    mov %eax, 0
    leave
    ret

    /*assembler code generated by gcc 3.2.3 with -O opition on redhat platform
    env: GCC: (GNU) 3.2.3 20030502 (Red Hat Linux 3.2.3-47.3)
    cmd: $ gcc -S -masm=intel -O emptyfun.c -o opt.asm */


    main:
    push %ebp
    mov %ebp, %esp
    sub %esp, 8
    and %esp, -16
    mov %eax, 0 ; i = 0;
    .L7: ; for( ; ; ; )
    inc %eax ; { i++;
    cmp %eax, 9 ; ( if i <=9 )
    jle .L7 ; continue;
    mov %eax, 0 ; }
    leave
    ret
     
    以下代码完成了 打印错误消息的功能:


    #include 
    <stdio.h>

    #include 
    <stdlib.h>

    #include 
    <unistd.h>

    #include 
    <limits.h>

    #include 
    <errno.h>

    #include 
    <stdarg.h>

    #define MAXLINE 2048

    #define DEBUG



    /*

     err_doit 将用户指定的字串和系统错误信息打印到指定的文件

     fileno 文件号

     error  用户定义字串





    */

    static void

    err_doit(
    int fileno, int error, const char *fmt, va_list ap)

    {

        
    char    buf[MAXLINE];

        
    int msglen;

        vsnprintf(buf, MAXLINE, fmt, ap);

        snprintf(buf
    +strlen(buf), MAXLINE-strlen(buf), ": %s\n", strerror(error));

        msglen  
    = strlen( buf );

        fdopen( fileno, 
    "ab" );

        fwrite( buf, msglen, 
    1, fdopen( fileno, "ab" ) );

    }

    inline 
    void dbg_err(const char * fmt, )

    {

    #ifdef DEBUG

        va_list        ap;

        va_start(ap, fmt);

        err_doit( fileno( stderr ), 
    0, fmt, ap);

        va_end(ap);

    #endif

    }



    int main()

    {

        dbg_err( 
    "my god!" );

        
    return 0;

    }




  • 相关阅读:
    JAVA中的浅拷贝与深拷贝
    Spring异步-@Async注解
    Spring 事务传播行为的使用
    DecimalFormat的使用
    Java编码问题原因以及解决
    Spring
    [TimLinux] docker CentOS7 入门——容器(1)
    [TimLinux] asciinema Linux终端录制工具嵌入私有web中
    [TimLinux] docker CentOS7安装docker-ce最新版
    [TimLinux] systemd 精通CentOS7系统启动systemd
  • 原文地址:https://www.cnblogs.com/diylab/p/1335199.html
Copyright © 2020-2023  润新知