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;
}
范晨鹏
------------------
软件是一种态度
成功是一种习惯