GCC優化與返回Local Variables
阿新 • • 發佈:2019-02-11
先看程式碼:
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了,所以列印的結果是正確的!