技术控

    今日:10| 主题:49195
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Goto对变量定义的影响

[复制链接]
安靜做個小孩 发表于 6 天前
62 2

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
[TOC]
  问题

  我们经常碰到有在goto后面定义变量,linux下编译不通过的问题(报错信息:crosses initialization of)。其实,只要注意一下就好了,今天问了一下公司前辈之后,也翻了些资料,记录一下,加深记忆,也希望能对一些人有些许帮助^_^。 ## 错误示例 代码:
  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.         goto Exit;
  6.         int a = 0;
  7. Exit:
  8.         return 0;
  9. }
复制代码
报错:
  1. [[email protected] c-c++]# g++ goto_study.cpp
  2. goto_study.cpp: In function 'int main()':
  3. goto_study.cpp:31: error: jump to label 'Exit'
  4. goto_study.cpp:29: error:   from here
  5. goto_study.cpp:30: error:   crosses initialization of 'int a'
复制代码
正确写法

  也不能说是正确的写法,只能说是编译OK的写法。直接上代码:
  
       
  • 写法一:  
  改变域,变成局部变量:
  1. int main()
  2. {
  3.     goto Exit;
  4.     {
  5.         int a = 0;
  6.     }
  7. Exit:
  8.         return 0;
  9. }
复制代码

       
  • 写法二  
  神奇的写法:
  1. int main()
  2. {
  3.     goto Exit;
  4.     int a;
  5.     a = 1;
  6. Exit:
  7.     cout << "a = " << a << endl;
  8.         return 0;
  9. }
复制代码
关键是还可以访问!结果:
  1. [[email protected] c-c++]# g++ goto_study.cpp
  2. [[email protected] c-c++]# ./a.out
  3. a = 1259648
复制代码
研究

  神奇的写法

  看到两个可以编译通过的写法之后,最纳闷的是写法二为毛可以编译通过,而且还能使用???
  
       
  • C++规定  
  参考[1][2]中提到了C++标准中的规定: > 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.
  意思是说:    如果一个程序的执行路径从代码中的点A(某个局部变量x还未定义)跳到代码中另一点B(该局部变量x已定义,并且定义的时候有初始化),那么编译器会报错。这样的跳跃可以是由于执行goto语句,或者是switch-case造成的。所以,在写法二中a是int类型,是一个POD类型,并且没有初始化,所以编译通过。但是,很明显:如果去使用这个变量a的时候,结果是未知的,就像前辈说的,没有意义,还不如不支持!那如果只在局部使用,完全可以用花括号括起来!网上也有人说到,C++规范虽然没有明确说明这样是错误的,但是变量的域的规定其实是隐性说这种做法是不可取的,见参考[4]。  
  
       
  • 隐性说明  
  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标记  
  参考[4]中提到,g++编译器默认是检查的,自己可以设置编译器的这个标记变成警告,未实践!!!
  查了下资料-fpermissive标记的作用是: 把代码的语法错误作为警告,并继续编译进程,所以就安全起见,这个角度就不要想了,还是老老实实码砖!
  POD类型

  参考[3],按照上面C++规定的说法,只要是POD类型,并且没有初始化都是可以编译通过的。看一段代码:
  1. #include <iostream>
  2. using namespace std;
  3. class A{
  4. public:
  5.     // 注意:和B不同的是有构造和析构函数, 所以编译报错
  6.     A(){}
  7.     ~A(){}
  8.     void testA(){
  9.         cout << "A::test." << endl;
  10.     }
  11. };
  12. class B{
  13. public:
  14.     void testB(){
  15.         cout << "B::test." << endl;
  16.     }
  17. };
  18. int main()
  19. {
  20.     goto Exit;
  21.     // int a = 1;    // windows ok.linux failed!
  22.     //A classA;        // failed:
  23.     B classB;        // success:
  24.     classB.testB();
  25. Exit:
  26.     classB.testB();
  27.     return 0;
  28. }
复制代码
结果:
  1. [[email protected] c-c++]# g++ goto_study.cpp
  2. [[email protected] c-c++]# ./a.out
  3. a = 1259648
  4. B::test.
复制代码
小结:

  
       
  • 以上代码在windows和linux下均编译通过和执行;   
  • A classA一句在windows和linux均编译不通过!因为A有构造和析构函数,不满足条件;   
  •       至于int a = 1;这样的写法在windows(msvc)下面能够通过就与C++规范不符了,求解释!!!  
  以下是POD类型(还是看英文吧):

  
       
  • int, char, wchar_t, bool, float, double是POD类型,这些类型的long/short and signed/unsigned版本也是;   
  • 指针(包括函数指针和成员指针)都是POD类型;   
  • enums枚举类型;   
  • POD的const和普通变量也都是;   
  • POD类型的class,struct和union也是。但要求所有的成员是public,并且没有基类,没有构造、析构函数和虚函数。静态成员在这些规则下也是。  
  总结

  
       
  • 最好不要用goto;   
  • goto后面不要跳过定义和初始化的变量,如果是POD类型可以先申明再定义,是不会编译报错的。但是不建议这么使用,可以看到如果执行语句跳过了赋值语句,那么变量的值是未知的,存在危险性;   
  • goto后面如果是局部的变量,可以用花括号括起来构成一个局部域,就安全了。  
  参考

  [1]    Getting a bunch of crosses initialization error  
  [2]    switch case、goto对变量定义的影响  
  [3]    “POD type” in C++  
  [4]    Statement goto can not cross pointer definition?  
  [5]    error: jump to label ‘foo’ crosses initialization of ‘bar’
友荐云推荐




上一篇:UITableView的Cell复用原理和源码分析
下一篇:Reuven Lerner: The case against Python 3
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

厮守→上帝 发表于 6 天前
一语道尽爱情的残忍。情到深处人孤。疾苦使人成熟,强项的人会感悟爱的真谛,而懦弱的人徒生怅恨。
回复 支持 反对

使用道具 举报

PKD 发表于 5 天前
连广告也信,读书读傻了吧
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表