GCC優化與返回值
Table of Contents
1 GCC優化與返回局部變量(Local variables)
1.1 實驗環境:debian6, gcc 4.4.5
1.2 進入正題:
先看代碼:
char* func(int a) { char xxxx[ 20 ] = "func test return"; return xxxx; } //爲了節約版面,這裏省略main函數的代碼
趕緊很明顯是錯誤的,返回棧上的局部變量。函數返回的時候變量已經不存在了!這樣編譯:
gcc xxx.c 有如下警告信息: return.c: In function ‘func’: return.c:21: warning: function returns address of local variable
返回結果“打印”是正確的!當然我還是懷疑結果的正確性!再寫測試代碼如下:
char* func(int a) { char xxxx[ 20 ] = "func test return"; return xxxx; } char* func1(int a) { char *xxxx="func1 test return"; return xxxx; } int main(int argc, char *argv[]) { char *ptr = func(100 ); printf( "first = %s\n", ptr); printf( "%s\n", func1(90 )); printf( "second = %s\n", ptr); return 0; }
這個測試用列是有特別用意的,調用函數func和func1的棧結構是一樣的。結果輸出是錯誤的!爲什麼呢?其實想象也是明白的,函數調用肯定是不會出錯,只是返回了棧上的地址而已,操作返回的地址纔會出錯。這也是指針的特性!說到這裏是否和GCC優化還是沒有扯傻瓜關係,下面我們加入優化選項觀察!這樣編譯:
gcc -O3 xxx.c 有如下警告信息: return.c: In function ‘func’: return.c:21: warning: function returns address of local variable
返回結果是正確的!對比兩總編譯方式的彙編:第一種:
0000000000400534 <func>: 400534: 55 push %rbp 400535: 48 89 e5 mov %rsp,%rbp 400538: 89 7d dc mov %edi,-0x24(%rbp) 40053b: c7 45 e0 66 75 6e 63 movl $0x636e7566,-0x20(%rbp) 400542: c7 45 e4 20 74 65 73 movl $0x73657420,-0x1c(%rbp) 400549: c7 45 e8 74 20 72 65 movl $0x65722074,-0x18(%rbp) 400550: c7 45 ec 74 75 72 6e movl $0x6e727574,-0x14(%rbp) 400557: c7 45 f0 00 00 00 00 movl $0x0,-0x10(%rbp) 40055e: 48 8d 45 e0 lea -0x20(%rbp),%rax 400562: c9 leaveq 400563: c3 retq
第二種:
0000000000400540 <func>: 400540: 48 8d 44 24 d8 lea -0x28(%rsp),%rax 400545: c3 retq 400546: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 40054d: 00 00
第二種直接把函數inline了,所以打印的結果是正確的!
1.3 總結
1.3.1 一定要儘量解決編譯時的警告
一定要解決加上-Wall -Wextra編譯選項以後產生的警告。不解決的前提是警告確實你需要的語義!像上面的返回局部變量是有警告提示的,如果解決就可以避免這樣的錯誤。
1.3.2 要與項目的構建環境保持一致和獨立性
當然也就是一致測試和分離測試。假如構建環境中默認是加了-O3。就不會即使發現這樣的問題。這就需要分離測試解決,但是話說回來比較好的構建環境因該要同時解決這兩個問題。
Date: 2012-05-08 11:14:49 CST
HTML generated by org-mode 6.33x in emacs 23