C++跳轉(zhuǎn)語(yǔ)句之Goto對(duì)變量定義的影響詳解
前言
goto語(yǔ)句也稱為無(wú)條件轉(zhuǎn)移語(yǔ)句,其基本形式如下 :
語(yǔ)句標(biāo)號(hào)由一個(gè)有效地標(biāo)識(shí)符和符號(hào)";"組成,其中,標(biāo)識(shí)符的命名規(guī)則與變量名稱相同,即由字母、數(shù)字和下劃線組成,且第一個(gè)字符必須是字母或下劃線。執(zhí)行g(shù)oto語(yǔ)句后,程序就會(huì)跳轉(zhuǎn)到語(yǔ)句標(biāo)號(hào)處,并執(zhí)行其后的語(yǔ)句。
通常goto語(yǔ)句與if條件語(yǔ)句連用,但是,goto語(yǔ)句在給程序帶來(lái)靈活性的同時(shí),也會(huì)使得使程序結(jié)構(gòu)層次不清,而且不易讀,所以要合理運(yùn)用該語(yǔ)句。
發(fā)現(xiàn)問(wèn)題
我們經(jīng)常碰到有在goto后面定義變量,linux下編譯不通過(guò)的問(wèn)題(報(bào)錯(cuò)信息:crosses initialization of)。其實(shí),只要注意一下就好了,今天問(wèn)了一下公司前輩之后,也翻了些資料,記錄一下,加深記憶,也希望能對(duì)一些人有些許幫助。
錯(cuò)誤示例代碼:
#include <iostream> using namespace std; int main() { goto Exit; int a = 0; Exit: return 0; }
報(bào)錯(cuò):
[root@localhost c-c++]# g++ goto_study.cpp goto_study.cpp: In function 'int main()': goto_study.cpp:31: error: jump to label 'Exit' goto_study.cpp:29: error: from here goto_study.cpp:30: error: crosses initialization of 'int a'
正確寫法
也不能說(shuō)是正確的寫法,只能說(shuō)是編譯OK的寫法。
直接上代碼:
寫法一:
改變域,變成局部變量:
int main() { goto Exit; { int a = 0; } Exit: return 0; }
寫法二
神奇的寫法:
int main() { goto Exit; int a; a = 1; Exit: cout << "a = " << a << endl; return 0; }
關(guān)鍵是還可以訪問(wèn)!結(jié)果:
[root@localhost c-c++]# g++ goto_study.cpp [root@localhost c-c++]# ./a.out a = 1259648
研究
神奇的寫法
看到兩個(gè)可以編譯通過(guò)的寫法之后,最納悶的是寫法二為毛可以編譯通過(guò),而且還能使用???
C++規(guī)定
參考[1][2]中提到了C++標(biāo)準(zhǔn)中的規(guī)定: > It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type (3.9) and is declared without an initializer.
意思是說(shuō):如果一個(gè)程序的執(zhí)行路徑從代碼中的點(diǎn)A(某個(gè)局部變量x還未定義)跳到代碼中另一點(diǎn)B(該局部變量x已定義,并且定義的時(shí)候有初始化),那么編譯器會(huì)報(bào)錯(cuò)。這樣的跳躍可以是由于執(zhí)行g(shù)oto語(yǔ)句,或者是switch-case造成的。所以,在寫法二中a是int類型,是一個(gè)POD類型,并且沒(méi)有初始化,所以編譯通過(guò)。但是,很明顯:如果去使用這個(gè)變量a的時(shí)候,結(jié)果是未知的,就像前輩說(shuō)的,沒(méi)有意義,還不如不支持!那如果只在局部使用,完全可以用花括號(hào)括起來(lái)!網(wǎng)上也有人說(shuō)到,C++規(guī)范雖然沒(méi)有明確說(shuō)明這樣是錯(cuò)誤的,但是變量的域的規(guī)定其實(shí)是隱性說(shuō)這種做法是不可取的,見(jiàn)參考[4]。
隱性說(shuō)明
Goto can't skip over definitions of variables, because those variables would not exist after the jump, since lifetime of variable starts at the point of definition. The specification does not seem to explicitly mention goto must not do that, but it is implied in what is said about variable lifetime.
-fpermissive標(biāo)記
參考[4]中提到,g++編譯器默認(rèn)是檢查的,自己可以設(shè)置編譯器的這個(gè)標(biāo)記變成警告,未實(shí)踐?。?!
查了下資料-fpermissive標(biāo)記的作用是: 把代碼的語(yǔ)法錯(cuò)誤作為警告,并繼續(xù)編譯進(jìn)程,所以就安全起見(jiàn),這個(gè)角度就不要想了,還是老老實(shí)實(shí)碼磚!
POD類型
參考[3],按照上面C++規(guī)定的說(shuō)法,只要是POD類型,并且沒(méi)有初始化都是可以編譯通過(guò)的。
看一段代碼:
#include <iostream> using namespace std; class A{ public: // 注意:和B不同的是有構(gòu)造和析構(gòu)函數(shù), 所以編譯報(bào)錯(cuò) A(){} ~A(){} void testA(){ cout << "A::test." << endl; } }; class B{ public: void testB(){ cout << "B::test." << endl; } }; int main() { goto Exit; // int a = 1; // windows ok.linux failed! //A classA; // failed: B classB; // success: classB.testB(); Exit: classB.testB(); return 0; }
結(jié)果:
[root@localhost c-c++]# g++ goto_study.cpp [root@localhost c-c++]# ./a.out a = 1259648 B::test.
小結(jié):
1、以上代碼在windows和linux下均編譯通過(guò)和執(zhí)行;
2、A classA一句在windows和linux均編譯不通過(guò)!因?yàn)锳有構(gòu)造和析構(gòu)函數(shù),不滿足條件;
3、至于int a = 1;這樣的寫法在windows(msvc)下面能夠通過(guò)就與C++規(guī)范不符了,求解釋!??!
以下是POD類型(還是看英文吧):
1、int, char, wchar_t, bool, float, double是POD類型,這些類型的long/short and signed/unsigned版本也是;
2、 指針(包括函數(shù)指針和成員指針)都是POD類型;
3、enums枚舉類型;
4、POD的const和普通變量也都是;
5、POD類型的class,struct和union也是。但要求所有的成員是public,并且沒(méi)有基類,沒(méi)有構(gòu)造、析構(gòu)函數(shù)和虛函數(shù)。靜態(tài)成員在這些規(guī)則下也是。
總結(jié)
1、最好不要用goto;
2、goto后面不要跳過(guò)定義和初始化的變量,如果是POD類型可以先申明再定義,是不會(huì)編譯報(bào)錯(cuò)的。但是不建議這么使用,可以看到如果執(zhí)行語(yǔ)句跳過(guò)了賦值語(yǔ)句,那么變量的值是未知的,存在危險(xiǎn)性;
3、goto后面如果是局部的變量,可以用花括號(hào)括起來(lái)構(gòu)成一個(gè)局部域,就安全了。
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
參考
[1]Getting a bunch of crosses initialization error
[2]>switch case、goto對(duì)變量定義的影響
[3]>“POD type” in C++
[4]>Statement goto can not cross pointer definition?
[5]>error: jump to label ‘foo' crosses initialization of ‘bar'
上一篇:C++ 類的構(gòu)造函數(shù)詳解及實(shí)例
欄 目:C語(yǔ)言
本文標(biāo)題:C++跳轉(zhuǎn)語(yǔ)句之Goto對(duì)變量定義的影響詳解
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/1959.html
您可能感興趣的文章
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10c++中inline的用法分析
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解
- 01-10深入C/C++浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式詳解
- 01-10深入理解C/C++混合編程


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什