搜索
bottom↓
12
返回列表 发新帖
楼主: takashiki

那些膜拜do...while(0)的都什么心态

  [复制链接]

出0入0汤圆

发表于 2016-10-10 11:03:35 | 显示全部楼层
习惯而已,我用过do while(0),而且经常用,只是想代码看起来方便,好理解。当然,用if else完全能实现的,这我也清楚,只是用if else有缩进格,看起来没有do while(0)那么直观!

出0入0汤圆

发表于 2016-10-11 16:51:17 | 显示全部楼层
两个我都用。工具哪个顺手用哪个。

刚好读到李笑来《新生 —— 七年就是一辈子》的这一章:⾮议、争论,与鄙视链,引用几段:

当我开始觉得争论完全是浪费时间的时候,才开始反应过来,原来讨论和争论并不⼀回事⼉,有核⼼上的差异:
    讨论的⽬标是为了让⾃⼰更明⽩;
    争论的⽬标是为了彻底说服对⽅;
⼀旦归结到这⾥,就反应过来了,争论是完全⽆⽤的,因为其实很难达到效果;讨论才是有意义的 —— ⾃⼰的进步才最重
要,不是吗?
进⼀步观察就明⽩了,绝⼤多数⼈不懂什么是讨论。在他们的脑⼦⾥,讨论和争论是没有被详细区分的。在他们眼⾥,意⻅
不合的时候,最好“和为贵”;若是⼀定要掰扯个明⽩,那就是“争论”,结局只有输赢。
。。。。
放弃争论很久之后,我发现了另外⼀个由此产⽣的惊喜:
    彻底逃离鄙视链。
不知道你有没有发现,⼀旦⾃⼰参与争论,⽆论结果如何 —— 通常当然不是另外⼀⽅⼼服⼝服,⽽是不欢⽽散 —— 双⽅都
开始(必须)鄙视对⽅,然后双⽅都沦为鄙视链中的某⼀环⽽已。

出150入640汤圆

发表于 2016-10-11 20:07:18 | 显示全部楼层
楼主非linux程序猿

出0入0汤圆

发表于 2016-10-11 20:35:21 | 显示全部楼层
比如你处理某个IC的底层驱动,比如IIC吧
可能在通讯过程中要加入各种异常判断,可能会用goto 语句,这个场景下可以用do{}while(0)break出来
  1. int XXOO_NI_MA_BI()
  2. {
  3.     char* ptr = Durex;

  4.     XXOO;

  5.     if(Durex == NULL)
  6.     {
  7.         goto END;
  8.     };

  9.    BUY_TaoTao;

  10.     if(Money == NULL)
  11.     {
  12.         goto END;
  13.     };

  14.     Quqianqian;

  15. END:
  16.     ChiPaomian();
  17.     return HOME;
  18. }
复制代码


可以变成:

  1. int XXOO_NI_MA_BI()
  2. {
  3. do{
  4.     char* ptr = Durex;

  5.     XXOO;

  6.     if(Durex == NULL)
  7.     {
  8.     break;
  9.     };

  10.    BUY_TaoTao;

  11.     if(Money == NULL)
  12.     {
  13.    break;
  14.     };

  15.     Quqianqian;
  16. }
  17. while(0);

  18. }
复制代码

出0入42汤圆

发表于 2016-10-11 21:48:31 | 显示全部楼层
武林高手打群架,吃瓜群众学姿势

出0入8汤圆

发表于 2016-10-11 22:38:12 来自手机 | 显示全部楼层
qq335702318 发表于 2016-10-11 20:35
比如你处理某个IC的底层驱动,比如IIC吧
可能在通讯过程中要加入各种异常判断,可能会用goto 语句,这个场 ...

我想你或许没仔细看帖子,没理解 LZ 的意思。
这样的做法他都知道,只是觉得这样做不妥。

出0入0汤圆

发表于 2016-10-11 23:51:33 | 显示全部楼层
掌握do...while(0)优化程序结构,是C语言进阶的需要经历的一步。LZ还是加强学习而不是因自己未掌握就断言没必要存在。前面多位大神如@flamma都做了说明,下面我贴几段项目中实际应用的代码:

代码1:

  1. /**
  2. * @brief 任务运行
  3. * @retval 任务状态
  4. */

  5. static int pt_run(struct pt *pt)
  6. {
  7.         static T_Time time_delay;
  8.        
  9.         PT_BEGIN(pt);
  10.        
  11.         //等待
  12.         time_delay = get_time();
  13.         PT_WAIT_UNTIL(pt,work_condition(&time_delay));
  14.        
  15.         do
  16.         {
  17.                 //判断当前是否是需要亮屏的界面
  18.                 if (gui_schedule_get_gui_now() == GUI_STOP_PROGRESS)
  19.                 {
  20.                         screen_lock_unlock();
  21.                        
  22.                         break;
  23.                 }
  24.                
  25.                 if (State_Lock == 0)
  26.                 {
  27.                         break;
  28.                 }
  29.                
  30.                 //处理按键
  31.                 deal_key();
  32.                 //判断是否锁屏
  33.                 if (sub_time_safe(get_time(),&Time_Update) > TIME_SCREEN_LOCK * 1000000)
  34.                 {
  35.                         //锁屏
  36.                         inf_lcd_display_set(OFF);
  37.                         State_Lock = 0;
  38.                         //设置新主频
  39.                         rcc_config(24);
  40.                 }
  41.         } while (0);
  42.        
  43.         PT_END(pt);
  44. }
复制代码


代码2:

  1. /**
  2. * @brief 读取节点
  3. * @param node_ptr 存放读取节点数据的指针.如果无节点则id为0xffff
  4. */

  5. void mobile_data_read(T_Link_Node_Ptr node_ptr)
  6. {
  7.         T_Link_Node_Ptr node;
  8.         uint16_t slot = 0;
  9.         uint32_t us = 0;
  10.         uint8_t cycle = 0;
  11.         uint16_t slot_num = 0;
  12.         uint16_t slot_tx = 0;
  13.         T_Link_Node_Ptr node_find;
  14.        
  15.         node_ptr->id = 0xffff;
  16.         node_ptr->down_cmd = 0xff;
  17.         node_ptr->bag_index = 0xffff;
  18.        
  19.         //得到当前周期
  20.         cycle = system_time_get_cycle();
  21.         //总时隙数
  22.         slot_num = cycle * SLOT_NUM_SECOND;
  23.         //得到当前时隙
  24.         slot = system_time_get_slot();
  25.        
  26.         //遍历:查看是否有移动点升级程序包请求
  27.         //获取根节点
  28.         node = Header_Ptr->next;
  29.         while (node != NULL)
  30.         {
  31.                 //判断是否是升级程序包请求
  32.                 if (node->cmd == CMD_UWB_REQ_UPDATE_BAG)
  33.                 {
  34.                         //判断请求的是否是本基站
  35.                         if (node->station_id == para_manage_read_id())
  36.                         {
  37.                                 //增加事物命令:升级程序包
  38.                                 node->down_cmd = CMD_UWB_ACK_UPDATE;
  39.                                 *node_ptr = *node;
  40.                                 //删除节点
  41.                                 delete_link_node(node);
  42.                                 return;
  43.                         }
  44.                 }
  45.                
  46.                 node = node->next;
  47.         }
  48.        
  49.         //遍历:查看是否有需要发送的事务命令
  50.         //获取根节点
  51.         node = Header_Ptr->next;
  52.         while (node != NULL)
  53.         {       
  54.                 //判断下发时隙是否大于最大时隙
  55.                 slot_tx = node->slot_recv + SLOT_INTERVAL_TX;
  56.                 if (slot_tx >= slot_num)
  57.                 {
  58.                         slot_tx -= slot_num;
  59.                         //时隙未到
  60.                         if (slot >= node->slot_recv && slot < slot_num)
  61.                         {
  62.                                 return;
  63.                         }
  64.                 }
  65.                
  66.                 //时隙未到
  67.                 if (slot < slot_tx)
  68.                 {
  69.                         return;
  70.                 }
  71.                
  72.                 do
  73.                 {
  74.                         //超时
  75.                         if (slot > slot_tx)
  76.                         {
  77.                                 //判断是否有事务命令
  78.                                 if (node->down_cmd != 0xff)
  79.                                 {
  80.                                         //日志
  81.                                         log_write_num_time_out_delete();
  82.                                 }
  83.                                 //删除节点
  84.                                 delete_link_node(node);
  85.                                 break;
  86.                         }
  87.                        
  88.                         //已到发送时隙
  89. #ifndef TEST_MOBILE_DATA
  90.                         //判断是否有事务命令
  91.                         if (node->down_cmd == 0xff)
  92.                         {
  93.                                 break;
  94.                         }
  95. #endif
  96.                        
  97.                         //判断是否到发送时间
  98.                         us = system_time_get_time();
  99.                         //时隙中的时间
  100.                         us -= (uint64_t)slot * SLOT_TIME / 10000;
  101.                         if (us < SLOT_TIME_TX)
  102.                         {
  103.                                 return;
  104.                         }
  105.                        
  106.                         //判断是否有同在此时隙的移动点且是入网事务命令
  107.                         node_find = node->next;
  108.                         while (1)
  109.                         {
  110.                                 if (node_find == NULL)
  111.                                 {
  112.                                         break;
  113.                                 }
  114.                                
  115.                                 if (node_find->slot_recv != node->slot_recv)
  116.                                 {
  117.                                         break;
  118.                                 }
  119.                                
  120.                                 if (node_find->down_cmd == CMD_UWB_JOIN)
  121.                                 {
  122.                                         node = node_find;
  123.                                         break;
  124.                                 }
  125.                                
  126.                                 node_find = node_find->next;
  127.                         }
  128.                        
  129.                         *node_ptr = *node;
  130.                         //删除节点
  131.                         delete_link_node(node);
  132.                         return;
  133.                 } while(0);
  134.                
  135.                 node = node->next;
  136.         }
  137. }
复制代码


以上代码当然可以用if...else实现,但用do...while(0)可以优化程序结构,便于阅读和后续维护。

出0入93汤圆

 楼主| 发表于 2016-10-12 06:23:59 | 显示全部楼层
jdh99 发表于 2016-10-11 23:51
掌握do...while(0)优化程序结构,是C语言进阶的需要经历的一步。LZ还是加强学习而不是因自己未掌握就断言没 ...

flamma做出的说明是MISRA,是从程序的安全性和健壮性考虑的。MISRA把两种都给干掉了,flamma的意思就是两种都不要用了。他举出的那个例子,你把goto全部换成break,结果一样坑。当然,他那个代码违反MISRA的地方多了去了,最主要的还不是goto,而是违反了“规则 14.1 (强制):不能有不可到达(unreachable )的代码。”我后续说编译器,就因为现代编译器基本上都能对这种失误给出warning。
MISRA基本上判处do...while(0)的死刑,你这是要闹哪样,是自己打脸还是看不懂汉字?

以上代码当然可以用if...else实现,但用do...while(0)可以优化程序结构,便于阅读和后续维护。
然而却踩了flamma的雷区:MISRA规定
规则 14.6 (强制):  对任何迭代语句至多只应有一条 break  语句用于循环的结束。

恭喜你,双重标准玩得透熟。坦白的说,我就是反对你这种的,为了干掉goto而去干掉goto,结果从一个坑跳到另一个坑。简单的,就goto;不想goto,就{}+if。狂热的支持某种用途并不广泛的偏门技术还要给自己找一堆站不住脚的理由,说得过去吗。
BTW:尤其上面有一楼大言不惭的“不懂他的精妙之处”,都比MISRA枪毙的真不知道精妙在哪里。

出0入0汤圆

发表于 2016-10-12 06:28:59 | 显示全部楼层
楼主思维没那么缜密就不要用goto了,18般兵器都有他们的特长之处,你不能因为鞭子容易甩到自己就说鞭子危险、是坨屎,那是因为你用的太弱,linux内核里随处都能看到goto的身影

出0入93汤圆

 楼主| 发表于 2016-10-12 06:32:33 | 显示全部楼层
qq335702318 发表于 2016-10-11 20:35
比如你处理某个IC的底层驱动,比如IIC吧
可能在通讯过程中要加入各种异常判断,可能会用goto 语句,这个场 ...

从头至尾我都没有反对goto,我反对的是教科书式的为了避免goto而非得改成do...while(0)的,一上来就说goto如何如何的不好,那我就说了,do...while(0)也不好,甚至还不如goto呢。同样,我也没有反对do...while(0),比如宏。为了不用goto就去用do...while(0),我并不觉得好,我反对的是这个。简单粗暴的就goto,自己仔细的控制流程不要乱搞,我觉得完全没有问题。
77楼祭出MISRA的大菜刀,从程序可靠性方面明文禁止了goto,但是也同时基本干掉了do...while(0),因此我觉得特意用这个玩意代替goto根本没有必要。

出0入93汤圆

 楼主| 发表于 2016-10-12 06:36:17 | 显示全部楼层
yerrmin 发表于 2016-10-12 06:28
楼主思维没那么缜密就不要用goto了,18般兵器都有他们的特长之处,你不能因为鞭子容易甩到自己就说鞭子危险 ...

不好意思,我没有说过不用goto啊。你确定我说过了?我只是反对do...while(0)代替goto啊。你们这样说到底是要闹哪样啊
我一直在说,goto不是不可以用啊。

出0入8汤圆

发表于 2016-10-12 08:50:33 | 显示全部楼层
yerrmin 发表于 2016-10-12 06:28
楼主思维没那么缜密就不要用goto了,18般兵器都有他们的特长之处,你不能因为鞭子容易甩到自己就说鞭子危险 ...

你真的错怪 LZ 了。
LZ 反对的是 do while (0) 取代 goto 的做法。

话说,熟悉 linux 内核的人来说一下?
linux 内核中,是原生 goto 多呢,还是 do while (0) 的做法多呢?

出0入8汤圆

发表于 2016-10-12 09:38:29 | 显示全部楼层
本帖最后由 security 于 2016-10-12 09:40 编辑
jdh99 发表于 2016-10-11 23:51
掌握do...while(0)优化程序结构,是C语言进阶的需要经历的一步。LZ还是加强学习而不是因自己未掌握就断言没 ...


诚然 do while (0) 是一种进阶的优化技巧,但我想 LZ 的 C 语言功力应该不浅。

优化技巧有利有弊,
利的地方,大家说了很多,包括你这些例子,
弊的地方,很多人都忽略了:
1、do while (0) 这货是一个循环控制语句,用这个来代替 goto,失去了原来的意义,用在这种场合,只是一种优化技巧,不能当做惯用范式,
2、你的第一个例子,do while (0) 的行数较少,这没太大关系,think 的代价可以忽略,因为我们可以一目十行,整个代码逻辑可以完整的映入眼帘,
3、问题在于你的第二个例子,do while (0) 的覆盖范围太大了,没法一目了然,我以为这是一个循环控制,然而,当代码翻页下去,发现最后是 while (0)...问题的症结就在这边,对此,我更喜欢直观易懂的代码,
4、第二个例子,更好的做法,是用子函数来重构。

所以说少用这个技巧,这只是一种优化技巧,不能当做惯用范式,
你可以去看下 linux 内核,看下是原生 goto 多,还是 do while (0) 多?
我不是 linux 猿,但我猜 goto 多。

出0入0汤圆

发表于 2016-10-12 09:44:12 | 显示全部楼层
jdh99 发表于 2016-10-11 23:51
掌握do...while(0)优化程序结构,是C语言进阶的需要经历的一步。LZ还是加强学习而不是因自己未掌握就断言没 ...

在你说楼主未掌握就断言的时候,建议你先仔细看一些帖子吧!
你这些结构,我改成goto,程序结构一样明朗,这个对c语言也没有进阶到哪里去!
这样就不知道是你应该加强学习还是别人加强学习了!

我并不否认goto的灵活度很高,但是说goto容易种bug就禁止而采用do-while-zero+break的人,
请问一下这种do-while-zero+break又安全到哪里去?而且就算不用goto,用if-else结构来处理,
程序结构也一样明朗!

犹如楼主说的,看到do-while以为是循环,看了一下while里的条件TM居然是个zero!无不无聊~

出0入0汤圆

发表于 2016-10-12 09:49:46 | 显示全部楼层
这就跟路上看人家穿的衣服不爽 然后去吐槽人家的穿衣方式一样   正是闲得慌,  呃  我也闲得慌, 还来回这一贴

出0入0汤圆

发表于 2016-10-12 09:54:57 | 显示全部楼层
恩,确实误会楼主了
不过,楼主也不要太过纠结,只要是不用维护别人的代码,别人想怎么都无所谓。怕就怕在要维护别人的,那就比较操蛋了

出0入8汤圆

发表于 2016-10-12 09:57:40 | 显示全部楼层
本帖最后由 security 于 2016-10-12 09:58 编辑
浮华一生 发表于 2016-10-12 09:49
这就跟路上看人家穿的衣服不爽 然后去吐槽人家的穿衣方式一样   正是闲得慌,  呃  我也闲得慌, 还来回这一 ...


这还是有点意义的。
可以让后来人看到 do while (0) 取代 goto 这种技巧的利弊,
而不是教科书式的禁用 goto,那我们换种方式来写 茴 字,毕竟 茴 字,有好几种写法,
嗯,就用 do while (0) 吧。

出0入0汤圆

发表于 2016-10-12 10:34:54 | 显示全部楼层
本帖最后由 qq335702318 于 2016-10-12 10:37 编辑

美观代码咯
  1. void Task_Today(void)
  2. {
  3. // 早上
  4. chi_zao_can();
  5. xiwan();
  6. song_haizi_shang_xue();
  7. shangban();
  8. //中午
  9. maicai();
  10. xicai();
  11. zhucai();
  12. chifan();
  13. shuijiao();
  14. // 晚上
  15. XXOO();
  16. XXOO();
  17. //
  18. ....
  19. };



  20. [code]void Task_Today(void)
  21. {
  22. // 早上
  23. do
  24.    {
  25.    chi_zao_can();
  26.    xiwan();
  27.    song_haizi_shang_xue();
  28.    shangban();
  29.    }
  30.    while(0);

  31. //中午
  32. do
  33.   {
  34.   maicai();
  35.   xicai();
  36.   zhucai();
  37.   chifan();
  38.   shuijiao();
  39.   }
  40.   while(0);

  41. // 晚上
  42. do
  43. {
  44.   XXOO();
  45.   XXOO();
  46. }
  47. while(0);
  48. //
  49. ....
  50. };
复制代码

出0入8汤圆

发表于 2016-10-12 10:40:10 | 显示全部楼层
本帖最后由 security 于 2016-10-12 10:43 编辑


我觉得这样并不美。

逻辑块应该重构,才更有意义:
1、用宏代替,宏里面可以用 do while (0)。
2、或者,这些用 inline 函数,or 子函数来代替。

而如果你是想直观的看到,早上、下午、晚上都干了什么的话,
那么直接加上 { } 更美,
就只要 { } ,不要 do 和 while (0)。

出0入0汤圆

发表于 2016-10-12 10:47:58 | 显示全部楼层
还有变量作用域的问题
void zhuang_B(void)
{
int A;
A=10086;
.....; //do something;
int B;
//装B,把A值装到B
B = A;
};

有些编译器会编译不过上面这个代码。

void zhuang_B(void)
{
int A;
A=10086;
.....; //do something;
do
  {
   int B;
   //装B,把A值装到B
   B = A;
  }while(0);
};

几乎所有编译器都能编译上面这个代码。

出0入8汤圆

发表于 2016-10-12 10:52:04 | 显示全部楼层
qq335702318 发表于 2016-10-12 10:47
还有变量作用域的问题

有些编译器会编译不过上面这个代码。

你这个例子属于作用域的问题,
作用域的解决方案,应该使用 { } 来解决,
而不是使用 循环控制语句 来解决,虽然里面附带了有作用域。

出0入0汤圆

发表于 2016-10-12 11:01:31 | 显示全部楼层
本帖最后由 qq335702318 于 2016-10-12 11:03 编辑
security 发表于 2016-10-12 10:52
你这个例子属于作用域的问题,
作用域的解决方案,应该使用 { } 来解决,
而不是使用 循环控制语句 来解 ...


据我所知 do{}while(0); 就那么几个作用啊
不过实际写的时候其实do..while(0);用的很少
主要都在宏里面

另一种可能性就是考虑程序的移植性和条件编译那方面咯




  1. #define 业务员编号 0
  2. ........

  3. void Task_拿下那个装B客户(int 给你A mS时间)
  4. {
  5.   Task_去客户那里喝茶();
  6.   Task_去客户那里聊天();
  7.   Task_去客户那里送样();
  8.   Task_去客户那里送礼();
  9.   if(时间>A)break;
  10. }while(业务员编号);
复制代码


这个例子里面,通过宏定义可以方便地修改代码某些细节的运行效果。
0号的业务员只会跑一次腿
而其他业务员会一直跑下去,直到任务超越时限

出0入8汤圆

发表于 2016-10-12 11:08:39 | 显示全部楼层
qq335702318 发表于 2016-10-12 11:01
据我所知 do{}while(0); 就那么几个作用啊
不过实际写的时候其实do..while(0);用的很少
主要都在宏里面

我想 do while (0) 的用途,应该就限于宏定义、和取代 goto,这两种场景,
出现在这些场景,还好理解点,
但更多的应该只让它出现在宏定义中。

你这边的例子,我只能说太灵活了,
在我看来,不可取,
对于智商需要不断充值的我来说,要想较快的看懂它,有点费脑子了。

出0入0汤圆

发表于 2016-10-12 11:11:34 | 显示全部楼层
security 发表于 2016-10-12 11:08
我想 do while (0) 的用途,应该就限于宏定义、和取代 goto,这两种场景,
出现在这些场景,还好理解点, ...

大哥 这是褒我还是在贬我

出0入8汤圆

发表于 2016-10-12 11:15:33 | 显示全部楼层
本帖最后由 security 于 2016-10-12 11:17 编辑
qq335702318 发表于 2016-10-12 11:11
大哥 这是褒我还是在贬我


不褒也不贬,
这种做法,我不赞同,
只是希望,你能了解,代码要尽量写简单、直观,你这边属于非常规的做法,少点为好。
你可以搜一下 KISS 原则(Keep it simple, stupid),Don't make me think 原则等。

出0入93汤圆

 楼主| 发表于 2016-10-12 11:21:07 | 显示全部楼层
qq335702318 发表于 2016-10-12 11:01
据我所知 do{}while(0); 就那么几个作用啊
不过实际写的时候其实do..while(0);用的很少
主要都在宏里面

你这个例子已经变态到完全颠覆了我的本意……
我的本意是反对do..while(0)替代goto,你这个就是循环:要么循环1次,要么循环到超时。

出0入0汤圆

发表于 2016-10-12 11:48:55 | 显示全部楼层
不能挣钱的都是没用的东西

出0入0汤圆

发表于 2016-10-12 12:43:49 | 显示全部楼层
以前不管看 c/c++/java书, 都强调goto破坏程序结构, 很长时间特别注意, 现在觉得自己真SB, 多一个套路, 比强迫症有意义的多.

出0入42汤圆

发表于 2016-10-12 13:33:15 | 显示全部楼层
开个玩笑。。。

如果只是为了避免使用goto而使用do...各种break...while(0),那么用switch语句也可以实现:

  1. fun(...)
  2. {
  3.   FILE * fp1 = NULL;
  4.   FILE * fp2 = NULL;
  5.   void * hdr = NULL;
  6.   
  7.   switch(0)
  8.   {
  9.     default:
  10.    
  11.     fp1 = fopen("file1","rb");
  12.     if(fp1 == NULL) break;
  13.    
  14.     fp2 = fopen("file2","wb");
  15.     if(fp2 == NULL) break;
  16.    
  17.     hdr = ModuleCreate(...);
  18.     if(hdr == NULL) break;
  19.    
  20.     //TODO
  21.     ...
  22.     //Done
  23.     break;
  24.   }
  25.   //exit function
  26.   if(fp1 != NULL) fclose(fp1);
  27.   if(fp2 != NULL) fclose(fp2);
  28.   if(hdr != NULL) ModuleDestroy(hdr);
  29. }
复制代码



很别扭吧?

用goto:
  1. fun(...)
  2. {
  3.   FILE * fp1 = NULL;
  4.   FILE * fp2 = NULL;
  5.   void * hdr = NULL;
  6.   
  7.   fp1 = fopen("file1","rb");
  8.   if(fp1 == NULL) goto exit_function;
  9.    
  10.   fp2 = fopen("file2","wb");
  11.   if(fp2 == NULL) goto exit_function;
  12.    
  13.   hdr = ModuleCreate(...);
  14.   if(hdr == NULL) goto exit_function;
  15.    
  16.   //TODO
  17.   ...
  18.   //Done
  19.   
  20. exit_function:
  21.   if(fp1 != NULL) fclose(fp1);
  22.   if(fp2 != NULL) fclose(fp2);
  23.   if(hdr != NULL) ModuleDestroy(hdr);
  24. }
复制代码


goto就是用来跳转的,一目了然。
如果实在觉得goto碍眼,可以这样:

  1. #define FUNC_EXIT(label) {goto label;}

  2. fun(...)
  3. {
  4.   FILE * fp1 = NULL;
  5.   FILE * fp2 = NULL;
  6.   void * hdr = NULL;
  7.   
  8.   fp1 = fopen("file1","rb");
  9.   if(fp1 == NULL) FUNC_EXIT(exit_function);
  10.    
  11.   fp2 = fopen("file2","wb");
  12.   if(fp2 == NULL) FUNC_EXIT(exit_function);
  13.    
  14.   hdr = ModuleCreate(...);
  15.   if(hdr == NULL) FUNC_EXIT(exit_function);
  16.    
  17.   //TODO
  18.   ...
  19.   //Done
  20.   
  21. exit_function:
  22.   if(fp1 != NULL) fclose(fp1);
  23.   if(fp2 != NULL) fclose(fp2);
  24.   if(hdr != NULL) ModuleDestroy(hdr);
  25. }
复制代码

出0入8汤圆

发表于 2016-10-12 13:45:25 | 显示全部楼层
wshtyr 发表于 2016-10-12 13:33
开个玩笑。。。

如果只是为了避免使用goto而使用do...各种break...while(0),那么用switch语句也可以实现 ...

你的 switch 例子,很有针对性。

最后的例子,说服力不够,
因为不止 goto 碍眼,标号 exit_function 也碍眼啊。

出0入93汤圆

 楼主| 发表于 2016-10-12 14:12:04 | 显示全部楼层
wshtyr 发表于 2016-10-12 13:33
开个玩笑。。。

如果只是为了避免使用goto而使用do...各种break...while(0),那么用switch语句也可以实现 ...

这个switch好,稍微修改一下就能符合MISRA C规范,值得do...while(0)膜拜党改弦更张大力发扬。

出0入0汤圆

发表于 2016-10-12 15:07:21 | 显示全部楼层
syj0925 发表于 2016-10-9 10:49
汗,举例而已,我们是讨论程序结构流程,你干嘛非得要编译

看这个贴子我总是有一种想笑出声来的感觉。

出0入0汤圆

发表于 2016-10-12 19:07:19 | 显示全部楼层
do{ }while(0);代替goto, 能够限制程序只能跳出当前层的循环。而goto是可以随便跳的,既然可以随便跳,就可能不小心跳过一些关键的程序过程:

String s1, s2 = 0;

goto state;
// 被goto 跳过
switch(A)
{
case 1:s1=1;break;

}
…..
……
state:
if(s1==1)return -1;

出0入0汤圆

发表于 2016-10-12 20:39:26 来自手机 | 显示全部楼层
security 发表于 2016-10-12 08:50
你真的错怪 LZ 了。
LZ 反对的是 do while (0) 取代 goto 的做法。


fs和usb driver/pinctrl/i2c/pm我就没看到过几个do while(0)。几乎全是goto,尤其是一个函数申请多个系统资源要按顺序释放的时候。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-19 00:07

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表