前段時間,發現同一段C++代碼在windows 、Linux下的運行結果居然不一樣,於是測試了一把。
我們都知道,C++中不同作用域中不同的變量是互不干擾的,可以在全局作用域、函數作用域聲明同樣名字的名字。局部作用域中的變量只在局部作用域中生效,在局部作用域之外是不可見的。
但在for語句中聲明的變量,屬於for語句所定義的局部作用域嗎?
實驗環境
visual stuio:visual studio2015; Release版本;x86平台
G++:Debian 4.9.2-10;編譯命令 g++ -std=c++11 test_para.cpp -o test_para
實驗一
代碼:
#include <iostream> void test_para(int i){ for (int a = 0; a <= 2; a++) { std::cout << a <<" "<<&a <<std::endl; } std::cout << a << " final " << &a << std::endl; } int main(){ test_para(1); return 0; }
windows運行結果:
0 0030FAE81 0030FAE82 0030FAE800C61040 final 00C61040
Linux運行結果
編譯失敗
error: 'a' was not declared in this scope
按照我的認知,在for語句中定義的變量屬於局部變量,因此離開for語句塊之后變量應該是不可見的,Linux下G++的編譯結果正是如此,a在函數作用域沒有聲明。WIndow下的結果就比較詭異,a既不是for語句種的‘a'(地址不同),而且a的值與a的地址居然是一樣的,maybe undefined。
實驗二
代碼:
#include <iostream> void test_para(int a){ for (int a = 0; a <= 2; a++) { std::cout << a <<" "<<&a <<std::endl; } std::cout << a << " final " << &a << std::endl; } int main(){ test_para(1); return 0; }
windows運行結果
0 0045F93C1 0045F93C2 0045F93C1 final 0045F940
Linux運行結果
0 0x7ffda0098e9c1 0x7ffda0098e9c2 0x7ffda0098e9c1 final 0x7ffda0098e8c
注意,代碼與實驗一的代碼差異非常小,僅僅是test_para的形參名也叫’a‘,與for語種的局部變量重名。在這段代碼中,Linux和Windows的結果是一樣的:函數作用域的‘a’與for語句種的‘a'是互不干擾的兩個變量。
實驗三
代碼:
#include <iostream> void test_para(int a){ for (a = 0; a <= 2; a++) { std::cout << a <<" "<<&a <<std::endl; } std::cout << a << " final " << &a << std::endl; } int main(){ test_para(1); return 0; }
windows運行結果
0 0035FD741 0035FD742 0035FD741 final 0035FD8
Linux運行結果
0 0x7ffe4838156c1 0x7ffe4838156c2 0x7ffe4838156c3 final 0x7ffe4838156c
實驗三的代碼與實驗二的代碼區別也很小,僅僅是for語句中直接使用了’a',而沒有定義‘a'(沒有寫成int a)。在Windows上,可以看到在函數作用域的’a'與for語句中的‘a'是兩個不同的變量(地址不同),但for語句塊種的並沒有定義啊,感覺是visual studio自行加了一個auto,將 for (a = 0; a <= 2; a++) 變成了 for (auto a = 0; a <= 2; a++)
在Linux上,函數作用域的’a'與for語句中的‘a'是同一個變量,這是比較符合常理的,既然for語句塊中用到了變量‘a',又沒有聲明,那么自然應該在上一級作用域種查找,也就是找到了函數作用域種的’a'
總結
可以看到,三次實驗中,只有第二次實驗Windows(vs)與Linux(g++)表現是一致的,第一次實驗與第三次實驗,Windows上的運行結果都不太符合預期,特別是實驗三,感覺visual studio有點畫蛇添足。不過,我也沒有查到權威資料,不知道windows linux在這個問題上的差異性是不是因為本身就是undefined,也許通過看匯編也能看出一些端倪。日常工作中如果要考慮平台兼容性,最好是比較明確的寫法,比如這里,函數形參和語句塊中的局部變量就不要用同樣的名字好了。