搜索
bottom↓
回复: 133

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

  [复制链接]

出0入93汤圆

发表于 2016-10-9 09:18:53 | 显示全部楼层 |阅读模式
我是旗帜鲜明的反对do...while(0)的,如果说goto是一坨shit,那么do...while(0)就是一堆shit,恶心之极,比goto恶心多了!
在宏定义中,do...while(0)确实有用,这个我不反对,我反对的是在程序代码中弄这个东西的家伙,明明一对{}解决的事情却来装高深还影响阅读。
不服的do...while(0)党来辩。

PS: 宏定义时,该语句能够将语句块变成不完整的语句,因此在使用if...else...时强制要求加上分号,而直接使用{}则会因为加上了分号使得else可能对应错误。但是在非宏定义时,这个前提条件不会存在,这个就根本没有存在的必要。

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2016-10-9 09:21:53 | 显示全部楼层
本帖最后由 ilcvm 于 2016-10-9 09:26 编辑

这个估计是为了不用goto吧,break就跳到while(0)后了。不过我自己没用过。

=============================

后来才看到原帖,其实原帖里其他人解释很清楚了。

出0入0汤圆

发表于 2016-10-9 09:27:25 | 显示全部楼层
正常程序中没有用过,goto也没有用过

出0入93汤圆

 楼主| 发表于 2016-10-9 09:28:54 | 显示全部楼层
ilcvm 发表于 2016-10-9 09:21
这个估计是为了不用goto吧,break就跳到while(0)后了。不过我自己没用过。


既然要goto,必定有一定的条件,总不至于无缘无故到处乱跑。那么,一个if足以,这个理由站不住脚。

出10入46汤圆

发表于 2016-10-9 09:39:10 | 显示全部楼层
请楼主举例来说明,你认为那些do{}while(0) 不合适的例子,以便大家讨论。

否则每个人理解不同,就是公说公有理婆说婆有理。

出0入0汤圆

发表于 2016-10-9 09:41:56 | 显示全部楼层
takashiki 发表于 2016-10-9 09:28
既然要goto,必定有一定的条件,总不至于无缘无故到处乱跑。那么,一个if足以,这个理由站不住脚。 ...


参见原帖例子和52,53楼解释。当然你可以把所有goto out;都替换成free(buffer); return result ;,这样代码显得累赘也容易遗漏。

出0入0汤圆

发表于 2016-10-9 09:45:56 | 显示全部楼层
就是为了break就跳到while(0)后, goto有时表达不了程序的一体性,有些结构用它会变得很美;
楼主看不起它就表明, 楼主写代码只关注逻辑, 不关注结构; 一般关注结构的, 就明白 do {} while(0) 的奇妙之处

出0入93汤圆

 楼主| 发表于 2016-10-9 09:50:59 | 显示全部楼层
ilcvm 发表于 2016-10-9 09:41
参见原帖例子和52,53楼解释。当然你可以把所有goto out;都替换成free(buffer); return result ;,这样代 ...

原帖52楼胡说八道,你也信?但就那个例子而言,LZ的if...else非常完备,有没有goto都是一样的,为什么你会相信他而不自己试试呢?

出0入93汤圆

 楼主| 发表于 2016-10-9 09:53:24 | 显示全部楼层
onepower 发表于 2016-10-9 09:45
就是为了break就跳到while(0)后, goto有时表达不了程序的一体性,有些结构用它会变得很美;
楼主看不起它就表 ...

跟goto有关系吗,表达程序格式if...else、for、while等等足够了,不需要这些花哨的东西。
不然你写一个这样的结构,我无法用该结构以及goto表述出来,那我认输。如果你写不出来,那你的代码就是一堆shit。敢打赌吗?

出0入0汤圆

发表于 2016-10-9 09:55:42 | 显示全部楼层
takashiki 发表于 2016-10-9 09:53
跟goto有关系吗,表达程序格式if...else、for、while等等足够了,不需要这些花哨的东西。
不然你写一个这 ...

有本事不用goto也不用dowhile(0)...

出0入0汤圆

发表于 2016-10-9 09:58:02 | 显示全部楼层
樓主,do...while(0)有著不可替代的用途,絕非你想想的這麼簡單,請把C學好後再吐槽吧

出0入93汤圆

 楼主| 发表于 2016-10-9 09:58:48 | 显示全部楼层
snoopyzz 发表于 2016-10-9 09:55
有本事不用goto也不用dowhile(0)...

空口无凭。你写一个出来,再来反对我。

出0入93汤圆

 楼主| 发表于 2016-10-9 09:59:26 | 显示全部楼层
sunnyqd 发表于 2016-10-9 09:58
樓主,do...while(0)有著不可替代的用途,絕非你想想的這麼簡單,請把C學好後再吐槽吧 ...

用事实来说明吧,吹牛逼谁不会

出0入0汤圆

发表于 2016-10-9 10:00:43 | 显示全部楼层
snoopyzz 发表于 2016-10-9 09:55
有本事不用goto也不用dowhile(0)...

有本事你保证 ""所有函数一个入口, 一个出口", 这个和 用不用 goto 和 do..while(0) 一个道理;
你有本事不用, 我有本事该用的地方就用;

出0入0汤圆

发表于 2016-10-9 10:03:58 | 显示全部楼层
虽然我没用过宏定义的do...while(0),但是看楼上说的也很有道理。
对于多条语句,我一般是用逗号隔开,如
#define x  a=b+c,b=c+d
如果语句太多,那还是用函数吧。

出0入0汤圆

发表于 2016-10-9 10:05:11 | 显示全部楼层
本帖最后由 sunnyqd 于 2016-10-9 10:07 编辑
takashiki 发表于 2016-10-9 09:59
用事实来说明吧,吹牛逼谁不会


那就举个例子跟你说明吧,但是跟你说明后,楼主你一定要发帖承认你的错误

#define DOTASK1(x) do{ \
func1(x);\
func2(x);\
}while(0)

#define DOTASK2(x) { \
func1(x);\
func2(x);\
}

那么我这样使用
if(...)
  DOTASK1(1);
else
  DOTASK1(2);


if(...)
   DOTASK2(1);
else
   DOTASK2(2);

哪个正确呢?

出0入8汤圆

发表于 2016-10-9 10:06:33 来自手机 | 显示全部楼层
sunnyqd 发表于 2016-10-9 10:05
那就举个例子跟你说明吧,但是跟你说明后,楼主你一定要发帖承认你的错误

#define DOTASK1(x) do{ \

楼主说宏定义中他不反对

出0入0汤圆

发表于 2016-10-9 10:08:59 | 显示全部楼层
一对do while 和 一堆 if() {} 我是选择了前者

出20入34汤圆

发表于 2016-10-9 10:09:21 | 显示全部楼层
原帖在哪

出0入93汤圆

 楼主| 发表于 2016-10-9 10:09:48 | 显示全部楼层
本帖最后由 takashiki 于 2016-10-9 10:11 编辑
sunnyqd 发表于 2016-10-9 10:05
那就举个例子跟你说明吧,但是跟你说明后,楼主你一定要发帖承认你的错误

#define DOTASK1(x) do{ \


到底是不认识字还是理解能力有限啊,我都特意用加粗表示

出0入0汤圆

发表于 2016-10-9 10:10:10 | 显示全部楼层
canspider 发表于 2016-10-9 10:06
楼主说宏定义中他不反对

这样子啊,那楼主得改一遍标题了,do...while(0)一眼就诱导成宏定义了

出0入0汤圆

发表于 2016-10-9 10:13:09 | 显示全部楼层
takashiki 发表于 2016-10-9 10:09
到底是不认识字还是理解能力有限啊,我都特意用加粗表示

标题请改成"非宏定义中do...while(0)"

出0入0汤圆

发表于 2016-10-9 10:14:05 | 显示全部楼层
函数要实现单入单出,如果不使用goto,就只能用do{}while(0)了

出0入93汤圆

 楼主| 发表于 2016-10-9 10:17:35 | 显示全部楼层
sunnyqd 发表于 2016-10-9 10:13
标题请改成"非宏定义中do...while(0)"

不改,省得有心人攻击。
难道你看贴只看标题的么

出0入93汤圆

 楼主| 发表于 2016-10-9 10:21:37 | 显示全部楼层
gonboy 发表于 2016-10-9 09:39
请楼主举例来说明,你认为那些do{}while(0) 不合适的例子,以便大家讨论。

否则每个人理解不同,就是公说 ...

没有不合适,只是看起来折腾。一看到do还以为是循环呢,结果,嗯,根本只执行一次,这不吃饱了撑得
原帖10L就非常扯淡。

出20入34汤圆

发表于 2016-10-9 10:22:48 | 显示全部楼层
takashiki 发表于 2016-10-9 10:21
没有不合适,只是看起来折腾。一看到do还以为是循环呢,结果,嗯,根本只执行一次,这不吃饱了撑得
原帖1 ...

楼主 原帖在哪

出0入0汤圆

发表于 2016-10-9 10:23:33 | 显示全部楼层
封装宏使用,使得习惯兼容函数使用。

出0入93汤圆

 楼主| 发表于 2016-10-9 10:25:17 | 显示全部楼层

http://www.amobbs.com/thread-5661061-1-1.html

出0入93汤圆

 楼主| 发表于 2016-10-9 10:31:22 | 显示全部楼层
syj0925 发表于 2016-10-9 10:14
函数要实现单入单出,如果不使用goto,就只能用do{}while(0)了


只能?if被吃了?

出0入8汤圆

发表于 2016-10-9 10:33:32 | 显示全部楼层
  1. int  fun()
  2. {
  3.     int result = 0;
  4.     char * buffer = malloc(100);
  5.         
  6.     do {
  7.         if(buffer == NULL)
  8.         {
  9.             result = -1;
  10.             break;
  11.         }
  12.         dosomething;
  13.        if(XXX)
  14.         {
  15.             if(XXX)
  16.             {
  17.                 result = 1;
  18.                 break;
  19.             }
  20.            dosomething;
  21.             else
  22.             {
  23.                 result = 2;
  24.                 break;
  25.             }  
  26.            dosomething;              
  27.         }
  28.        dosomething;
  29.         else
  30.         {
  31.             result = 3;
  32.             break;
  33.         }
  34.         dosomething;
  35.     } while (false);

  36.     free(buffer);
  37.     return result ;

  38. }
复制代码

那如果是这样呢?能用一个{}代替?

出0入93汤圆

 楼主| 发表于 2016-10-9 10:34:58 | 显示全部楼层
liwey 发表于 2016-10-9 10:08
一对do while 和 一堆 if() {} 我是选择了前者

说实在的,谁然你这个答案不能令我满意,但目前为止,比起其他楼层,只有你这个才能令人信服一点。我并不觉得if...else没有什么不好,流程清晰,代码折叠后一目了然,只是缩进确实多了点。

出0入93汤圆

 楼主| 发表于 2016-10-9 10:36:33 | 显示全部楼层
如果 发表于 2016-10-9 10:33
那如果是这样呢?能用一个{}代替?

请先确认你的代码能通过编译。else前面对应啥了?C初学者还是一边看戏去吧。

出0入0汤圆

发表于 2016-10-9 10:39:15 | 显示全部楼层
takashiki 发表于 2016-10-9 10:31
只能?if被吃了?

if是可以,但是if嵌套太多,结构就比较乱,如下函数,你改为if试一下
bool Execute()
{
   // 分配资源
   int *p = new int;

   bool bOk(true);
   do
   {
      // 执行并进行错误处理
      bOk = func1();
      if(!bOk) break;

      bOk = func2();
      if(!bOk) break;

      bOk = func3();
      if(!bOk) break;

      // ..........

   }while(0);

    // 释放资源
    delete p;   
    p = NULL;
    return bOk;
   
}

出0入8汤圆

发表于 2016-10-9 10:40:37 | 显示全部楼层
takashiki 发表于 2016-10-9 10:36
请先确认你的代码能通过编译。else前面对应啥了?C初学者还是一边看戏去吧。 ...
  1. int  fun()
  2. {
  3.     int result = 0;
  4.     char * buffer = malloc(100);
  5.         
  6.     do {
  7.         if(buffer == NULL)
  8.         {
  9.             result = -1;
  10.             break;
  11.         }
  12.         dosomething;
  13.        if(XXX)
  14.         {
  15.             if(XXX)
  16.             {
  17.                 result = 1;
  18.                 break;
  19.             }
  20.            dosomething;
  21.             if(xx)
  22.             {
  23.                 result = 2;
  24.                 break;
  25.             }  
  26.            dosomething;              
  27.         }
  28.        dosomething;
  29.         if(xx)
  30.         {
  31.             result = 3;
  32.             break;
  33.         }
  34.         dosomething;
  35.     } while (false);

  36.     free(buffer);
  37.     return result ;

  38. }
复制代码

只是随便改了下,没理解我的意思,你还是算了吧

出0入0汤圆

发表于 2016-10-9 10:43:53 | 显示全部楼层
本帖最后由 codefish 于 2016-10-9 10:49 编辑

当认真理解do while(0)的奇妙之处,
才知道自己无知。

我当初因为无知,所以看不惯do while(0).

我现在很习惯看别人用do while(0),虽然我自己很少主动这样用。

出0入93汤圆

 楼主| 发表于 2016-10-9 10:45:19 | 显示全部楼层
syj0925 发表于 2016-10-9 10:39
if是可以,但是if嵌套太多,结构就比较乱,如下函数,你改为if试一下
bool Execute()
{

你确信bool bOk(true);可以通过编译?

出0入0汤圆

发表于 2016-10-9 10:49:13 | 显示全部楼层
takashiki 发表于 2016-10-9 10:45
你确信bool bOk(true);可以通过编译?

汗,举例而已,我们是讨论程序结构流程,你干嘛非得要编译

出0入93汤圆

 楼主| 发表于 2016-10-9 10:53:40 | 显示全部楼层
如果 发表于 2016-10-9 10:40
只是随便改了下,没理解我的意思,你还是算了吧

好,我改。你用break控制流程,别怪我用其他方式控制流程。

写来简单地,连我都不推荐的。
  1. int fun_free(char* buffer, int status){
  2.         if(buffer)
  3.                 free(buffer);
  4.         return status;
  5. }

  6. int  fun()
  7. {
  8.     int result = 0;
  9.     char * buffer = malloc(100);
  10.         
  11.         if(buffer == NULL)
  12.                         return fun_free(NULL, -1);
  13.        dosomething;
  14.        if(XXX)
  15.         {
  16.             if(XXX)
  17.                                 return fun_free(buffer, 1);
  18.            dosomething;
  19.             if(xx)
  20.                                 return fun_free(buffer, 2);
  21.            dosomething;              
  22.         }
  23.        dosomething;
  24.         if(xx)
  25.                         result = fun_free(buffer, 3);
  26.         dosomething;
  27.     return fun_free(NULL, result);
  28. }
复制代码

然后就是一堆if...else搞成的,你懂得,绝不是你认为就无法实现。

出0入8汤圆

发表于 2016-10-9 10:56:05 | 显示全部楼层
takashiki 发表于 2016-10-9 10:53
好,我改。你用break控制流程,别怪我用其他方式控制流程。

写来简单地,连我都不推荐的。

你都不推荐,就说明很繁琐,一个do while(0)可以解决的你就接受不了?

出0入93汤圆

 楼主| 发表于 2016-10-9 10:58:10 | 显示全部楼层
syj0925 发表于 2016-10-9 10:39
if是可以,但是if嵌套太多,结构就比较乱,如下函数,你改为if试一下
bool Execute()
{

你这个我宁愿写一堆if,我不觉得结果乱啊。事实上,像你这种一大堆C++代码的,我宁愿try...finally...或者单弄一个函数了

出0入93汤圆

 楼主| 发表于 2016-10-9 10:59:29 | 显示全部楼层
如果 发表于 2016-10-9 10:56
你都不推荐,就说明很繁琐,一个do while(0)可以解决的你就接受不了?

繁琐吗?比你的还简单好吧。我只是不想在一个函数中申请资源另一个函数中释放资源而已。

出0入93汤圆

 楼主| 发表于 2016-10-9 11:10:27 | 显示全部楼层
syj0925 发表于 2016-10-9 10:39
if是可以,但是if嵌套太多,结构就比较乱,如下函数,你改为if试一下
bool Execute()
{


还是来改写你这个吧,你这个完全没有说服力。改之后结构更清晰,代码更方便。
  1. bool Execute()
  2. {
  3.    // 分配资源
  4.    int *p = new int;

  5.         // 执行并进行错误处理
  6.         bool bOk = func1();
  7.         if(bOk) bOk = func2();
  8.         if(bOk) bOk = func3();
  9.         if(bOk) bOk = ...
  10.         // ..........

  11.     // 释放资源
  12.     delete p;   
  13.     p = NULL;
  14.     return bOk;   
  15. }
复制代码

出0入0汤圆

发表于 2016-10-9 11:15:05 | 显示全部楼层
谁爱这样用,随他用就是,管他作甚

出0入0汤圆

发表于 2016-10-9 11:29:04 | 显示全部楼层
takashiki 发表于 2016-10-9 11:10
还是来改写你这个吧,你这个完全没有说服力。改之后结构更清晰,代码更方便。

...

你好像没看明白程序吧,func执行失败是要退出的,你这样写是可以,但是每个if都要去执行,不觉得很怪吗?

出0入0汤圆

发表于 2016-10-9 11:39:39 | 显示全部楼层
看个人习惯吧   反正我是没用过

出0入93汤圆

 楼主| 发表于 2016-10-9 11:46:56 | 显示全部楼层
本帖最后由 takashiki 于 2016-10-9 11:48 编辑
syj0925 发表于 2016-10-9 11:29
你好像没看明白程序吧,func执行失败是要退出的,你这样写是可以,但是每个if都要去执行,不觉得很怪吗? ...


找一本微软COM编程的书看看吧,看看人家是怎么编程的。大括号都长到1公里开外了。
每个if只是判断了返回值,占用不了多少CPU资源。

出0入0汤圆

发表于 2016-10-9 11:52:55 | 显示全部楼层
takashiki 发表于 2016-10-9 11:46
找一本微软COM编程的书看看吧,看看人家是怎么编程的。大括号都长到1公里开外了。
每个if只是判断了返回 ...

看来没讨论的必要了

出190入0汤圆

发表于 2016-10-9 11:53:47 | 显示全部楼层
每个人编程风格不一样可以理解的啊,不知道LZ争这个问题意义在哪?

出0入0汤圆

发表于 2016-10-9 11:57:15 | 显示全部楼层
青菜,,,萝卜,,各有喜爱。。

出0入0汤圆

发表于 2016-10-9 12:06:14 来自手机 | 显示全部楼层
宏定义用,其他真没发现优点,学习一下。

出0入0汤圆

发表于 2016-10-9 12:10:02 | 显示全部楼层
一般代码中的do-while-0,如果不是为了break,就是有强迫症不要空的大括号的。

C的while, do-while, for基本就是为了代码风格的设计的,完全根据自己爱好选择。

出0入93汤圆

 楼主| 发表于 2016-10-9 12:12:55 | 显示全部楼层
knight_sh 发表于 2016-10-9 11:53
每个人编程风格不一样可以理解的啊,不知道LZ争这个问题意义在哪?

就在于看不惯那些把goto看做洪水猛兽的非得自己另整一套的人。goto不能滥用,但也不是不能用。而这个呢,除了宏定义外,基本没有什么用,还不如goto呢。

出0入93汤圆

 楼主| 发表于 2016-10-9 12:17:25 | 显示全部楼层
dr2001 发表于 2016-10-9 12:10
一般代码中的do-while-0,如果不是为了break,就是有强迫症不要空的大括号的。

C的while, do-while, for基 ...

强迫症……我竟无言以对
所有的循环都可以用while代替,确实是代码风格的问题。

出0入8汤圆

发表于 2016-10-9 12:17:29 来自手机 | 显示全部楼层
syj0925 发表于 2016-10-9 11:52
看来没讨论的必要了

这种讨论基本就像:空格和 TAB,没有结论。
不过我是站 LZ 这队的,我不喜好用这技能,我喜欢代码看起来是什么样,最好它就刚好是那样。

不过看你的例子,不用 do while 0,不用 goto,不用 if 一直重复判断,这样来做,你觉得如何:
1、将这部分逻辑抽取为一个函数,一旦错误,就 return,结束函数流程
2、改成子函数的做法,我想这也是一种比较传统的解决方案。

出0入0汤圆

发表于 2016-10-9 12:22:17 | 显示全部楼层
takashiki 发表于 2016-10-9 12:12
就在于看不惯那些把goto看做洪水猛兽的非得自己另整一套的人。goto不能滥用,但也不是不能用。而这个呢, ...

其实 ""goto不能滥用,但也不是不能用" 这句话就已经说明其是洪水猛兽了.  洪水就没用吗? 猛兽只要你比他更猛你也可以把它作为坐骑.  既然容易滥用, 那么在几乎无需花额外代价的情况下能避开不好吗? 也许你是高手, 但不是所有能接触到代码的都是高手. 代码很多时候不是光写给自己看的.

出0入93汤圆

 楼主| 发表于 2016-10-9 12:23:57 | 显示全部楼层
liwey 发表于 2016-10-9 12:22
其实 ""goto不能滥用,但也不是不能用" 这句话就已经说明其是洪水猛兽了.  洪水就没用吗? 猛兽只要你比他 ...

恩,不能滥用goto就改为滥用do...while(0),你觉得真的OK?

出0入93汤圆

 楼主| 发表于 2016-10-9 12:27:09 | 显示全部楼层
liwey 发表于 2016-10-9 12:22
其实 ""goto不能滥用,但也不是不能用" 这句话就已经说明其是洪水猛兽了.  洪水就没用吗? 猛兽只要你比他 ...

http://www.amobbs.com/thread-5661061-1-1.html LZ那样用,我就并不觉得是滥用,完全没有必要为了避免他而去另搞一套标准,虽然他根本没有什么作用。

出0入8汤圆

发表于 2016-10-9 12:29:41 | 显示全部楼层
takashiki 发表于 2016-10-9 12:23
恩,不能滥用goto就改为滥用do...while(0),你觉得真的OK?

不能滥用是因为有风险,所以尽量避免用goto,你觉得do while(0)有风险?只是不符合你的代码风格而已。   
注:我程序里偶尔用到的都是goto,从来没用过do while(0);但是真没觉得这样不好,能用就用

出0入0汤圆

发表于 2016-10-9 12:30:40 | 显示全部楼层
takashiki 发表于 2016-10-9 12:17
强迫症……我竟无言以对
所有的循环都可以用while代替,确实是代码风格的问题。 ...

我认为,基本上,do-while-0的使用就是个代码风格问题。
用了能让代码清晰高效就用,有别的更好的描述方式就不用。

C本来就是ASM的抽象但不完全高层,所以是相对灵活的。
用户自行在效率、可读性、可维护性等等方便自行权衡,选择适当的方式描述。

类似的,还有屏蔽代码块是用#if 0 / #endif还是if(0) {}这种,etc。

出0入0汤圆

发表于 2016-10-9 12:32:26 | 显示全部楼层
takashiki 发表于 2016-10-9 12:27
http://www.amobbs.com/thread-5661061-1-1.html LZ那样用,我就并不觉得是滥用,完全没有必要为了避免他 ...

我不是说这里滥用了, 但是goto容易被滥用是否已经有公论了? 这个例子改成非goto模式是不是也无需什么代价? 如果这两条满足的话, 那么尽可能的避免goto这个结论就没有错. 就如一条独木桥, 一条康庄大道, 到达目的地时间基本一致的话. 你艺搞人胆大选独木桥没问题, 但是前提是你每次都必须判断正确他是否足够安全, 否则....

出0入0汤圆

发表于 2016-10-9 12:34:36 | 显示全部楼层
takashiki 发表于 2016-10-9 11:46
找一本微软COM编程的书看看吧,看看人家是怎么编程的。大括号都长到1公里开外了。
每个if只是判断了返回 ...

COM的interface是IDL语言机器编译的,

那个不是手工写的哈

出110入26汤圆

发表于 2016-10-9 12:43:46 | 显示全部楼层
do while 的特点是可以保证大括号里面的代码能执行至少一次,抛开这个一点来讨论就是耍流氓。

出0入0汤圆

发表于 2016-10-9 12:53:48 | 显示全部楼层
基本用到  do{}while(0) 的地方有两种,

一种宏定义,是防止失误。
一种异常退出释放资源,也是防止失误,感觉比一堆 if 好。

个人感觉在这两种场景下使用  do{}while(0) 确实不错。

看了网上一些资料也就局限在这两个场景了。

PS:至于楼主想写成什么样就写成什么样呗,反正编译出来机器认得就行了。 代码风格是为了方便人看和避免失误的。反正我在这两种场景会用 do{}while(0)

出0入25汤圆

发表于 2016-10-9 12:55:59 | 显示全部楼层
本帖最后由 XIVN1987 于 2016-10-9 12:57 编辑

我觉得楼主这样不好!
你不喜欢用不用就好了,可你这样上来专门发个帖子说别人的代码“是一堆shit”、“恶心之极”,说别人“装高深”,你不怕这样写代码的人在心里骂你吗?说不定脾气不好的会直接跟帖骂你,,这不影响心情吗??

毕竟这只是个风格、喜好问题,又不存在对错,,争论又能争出个什么??
比如由来已久的tab应该2空格、4空格还是8空格,起始大括号换行还是不换行这类的问题争论过多少年、吵过多少次,,可最终谁又说服谁了吗??辩出个真理来了吗?
坚持自己的喜好就好了,别管人家怎么写,??

出0入0汤圆

发表于 2016-10-9 12:56:45 | 显示全部楼层
着帖子的意义是?楼主想说服别人?

出0入0汤圆

发表于 2016-10-9 13:02:57 | 显示全部楼层
恰恰相反,我经常使用goto和do while(0)。
do while(0)在宏定义中有不可替代的用途。
goto则是在驱动中用起来太酸爽了,各种异常处理。

出0入93汤圆

 楼主| 发表于 2016-10-9 13:29:14 | 显示全部楼层
jm2011 发表于 2016-10-9 12:34
COM的interface是IDL语言机器编译的,

那个不是手工写的哈

使用啊大哥,谁去翻译IDL啊?

类似这样的:
  1. HRESULT hr = CoCreateXXX (xxx, obj);
  2. if(hr == S_OK){
  3.   hr = obj->QueryInterface(IID_XXX, obj2);
  4.   obj->Release();
  5.   if(hr == S_OK){
  6.     hr = obj2->get_XXX(XXX, obj3);
  7.     if(hr == S_OK){
  8.        hr = obj3->DoSomeThing();
  9.     }
  10.     obj2->Release();
  11.   }
  12. }
复制代码

出0入0汤圆

发表于 2016-10-9 13:36:59 | 显示全部楼层
goto之所以被推荐不使用或者少使用是因为goto功能太强大,如果滥用会造成很多问题,比如不小心跳过一些值的初始化,严重一些的写出上下乱跳的面条代码而难以维护。当然一些固定情景的goto使用,确实会带来好处,比如函数末尾资源释放,跳出多重循环(这一点还是有一定的争议)。do-while(0)的这种写法为啥会出现,就是因为它基本上是某种无害的goto使用情景的替代写法。你大概会说:那为啥不直接用goto? 请你试想一下大规模开发,几十人写代码,水平良莠不齐,是直接禁止goto方便,还是代码reveiw每条goto语句的应用场景方便?

出10入46汤圆

发表于 2016-10-9 13:40:47 | 显示全部楼层
songfei.org 发表于 2016-10-9 12:53
基本用到  do{}while(0) 的地方有两种,

一种宏定义,是防止失误。

赞同!
do{}while(0) 常用的就这两个场景。 其它的场景一般没有必要用。
如果为了规矩代码,看起来舒服,可以直接用 { },  建议不要用 do{}while(0)。

楼主没必要过于纠结此问题。
每个人都有自己的一套编程方法。
最主要的是在于规矩,易阅读(嵌入式同时需要考虑效率和可优化特性),便于后期维护。

尽量少用*,**,***,****(不容易理解的指针模式),+-*/(无括号靠自己判断优先级)等,老学究的编程方式即可。

至于Tab 是2格,4格还是 空格等,完全可以靠格式化来解决。

出10入46汤圆

发表于 2016-10-9 13:42:51 | 显示全部楼层
goto 不建议用的主要原因,在于不利于阅读,容易造成后期开发人员的逻辑混乱。

并不是说不让用,能不用,尽量少用而已。

作为开发的强制禁止使用 goto ,也并不是不可。

出10入46汤圆

发表于 2016-10-9 13:44:44 | 显示全部楼层
不过asm工程师,一般有强迫症,使用 goto.  

出0入0汤圆

发表于 2016-10-9 13:46:15 来自手机 | 显示全部楼层
最简单的,比如要申请内存,资源,锁,一个一个按顺序申请,函数结束后释放,一个申请失败也按顺序释放的情况(内核驱动很常见)。以goto比do..while(0)看起来要清爽不少。

出0入0汤圆

发表于 2016-10-9 14:12:57 | 显示全部楼层
gonboy 发表于 2016-10-9 13:42
goto 不建议用的主要原因,在于不利于阅读,容易造成后期开发人员的逻辑混乱。

并不是说不让用,能不用, ...

那个文献,那个公司的协定说强制禁止?
短范围的goto会让程序更加容易阅读!

出0入0汤圆

发表于 2016-10-9 14:50:07 | 显示全部楼层
do..while(0)还真没用过,关键是不会
我一般是单独封装一个函数来解决这个问题的
或者是想一个别的逻辑避开

出0入0汤圆

发表于 2016-10-9 14:53:59 | 显示全部楼层
楼主的命题,我感觉可以用以下这个例子来概括:
延时函数1
void delay(void)
{
    for (volatile int i = 0; i < 1000; i++);
}
延时函数2
void delay(void)
{
    volatile int i = 1000;
    while(i--);
}

出0入0汤圆

发表于 2016-10-9 15:15:49 | 显示全部楼层
没必要为这个争论吧!习惯用哪个就用哪个。

大家争论前先看看这个贴吧!
因使用空格与Tab键的分歧而分手,视频的最后一段笑喷了
http://www.amobbs.com/forum.php? ... 0&highlight=tab
--------------------
男女两名程序员正一边编程一边约会,小伙子忍受不了姑娘使用空格键缩进,认为Tab键更节省文件体积,最后愤然离去,声称绝对不会和用空格键缩进的人滚床单,以免孩子面临艰难的人生抉择……
自己看吧:
http://v.youku.com/v_show/id_XMTYzMDQ3ODgxMg==.html

出0入0汤圆

发表于 2016-10-9 16:10:09 | 显示全部楼层
qq开始学单片机 发表于 2016-10-9 14:12
那个文献,那个公司的协定说强制禁止?
短范围的goto会让程序更加容易阅读! ...

举个例子:Misra-c 任何版本都禁止使用goto。

出100入143汤圆

发表于 2016-10-9 16:10:32 | 显示全部楼层
songfei.org 发表于 2016-10-9 12:53
基本用到  do{}while(0) 的地方有两种,

一种宏定义,是防止失误。

同道中人

出0入0汤圆

发表于 2016-10-9 16:22:47 | 显示全部楼层
codefish 发表于 2016-10-9 10:43
当认真理解do while(0)的奇妙之处,
才知道自己无知。

硬了在软,软了再硬,

出0入0汤圆

发表于 2016-10-9 16:24:50 | 显示全部楼层
flamma 发表于 2016-10-9 16:10
举个例子:Misra-c 任何版本都禁止使用goto。

Misra-c还规定不能用逗号运算符,不能使用动态堆的内存分配”,限制malloc、free等程序的使用呢!这个例子不适合!

出0入0汤圆

发表于 2016-10-9 16:27:12 | 显示全部楼层
能避免就避免用GOTO,避免不了就大胆用。。别纠结。。。

出0入0汤圆

发表于 2016-10-9 16:36:32 | 显示全部楼层
C++相对其他语言来说最恶心的一点就是有try catch,没finally

出0入0汤圆

发表于 2016-10-9 16:38:27 | 显示全部楼层
其他语言中肯定没有这么用do while(0)的,都用try catch finally解决了。

出0入0汤圆

发表于 2016-10-9 16:43:34 | 显示全部楼层
qq开始学单片机 发表于 2016-10-9 16:24
Misra-c还规定不能用逗号运算符,不能使用动态堆的内存分配”,限制malloc、free等程序的使用呢!这个例 ...

为何不行。至少我拿到个第三方库如果符合Misra-c规范,我就会觉得更安全。另外Misra-c规范除了可读性的规定无所谓外,其他规定可以减少bug的概率是不争的事实。在很多嵌入式系统内存受限的情况下,小心的使用malloc,free难道不对。其实很多长期工作的系统为安全起见根本就不使用malloc,free。

出300入477汤圆

发表于 2016-10-9 16:50:28 | 显示全部楼层
本帖最后由 redroof 于 2016-10-9 21:10 编辑
lcofjp 发表于 2016-10-9 16:36
C++相对其他语言来说最恶心的一点就是有try catch,没finally


经典C++是设计为使用局部变量的析构函数来释放资源的。
人家设计的时候就不需要finally

当然实际上windows上的C++编译器都扩展了finally关键字。
比如VC/BCB里面用 __finally 就行了,语义和java的finally一样。

出0入0汤圆

发表于 2016-10-9 16:51:44 | 显示全部楼层
flamma 发表于 2016-10-9 16:43
为何不行。至少我拿到个第三方库如果符合Misra-c规范,我就会觉得更安全。另外Misra-c规范除了可读性的规 ...

为了内存的高效利用,动态内存分配的使用是很有必要的,而masra-c所涉及的领域要求安全性太过严格,
而goto一直都被叮嘱谨慎使用,连malloc和free,逗号运算符都禁止使用的masrc-c,那么被禁止也很正常。
而我们这里讨论是符合通用大众,自然这么严格的masrc-c就不是讨论的范畴之内了!

出0入93汤圆

 楼主| 发表于 2016-10-9 17:09:15 来自手机 | 显示全部楼层
flamma 发表于 2016-10-9 16:43
为何不行。至少我拿到个第三方库如果符合Misra-c规范,我就会觉得更安全。另外Misra-c规范除了可读性的规 ...

符合misra的确实更安全,但他不是为资源受限的系统设置的,更不会考虑效率,主要考量还是程序健壮性。misra建议禁止联合体,你难道都改用指针强制转换,更不安全是吧。合适的场合用合适的代码,未必不行。

出0入0汤圆

发表于 2016-10-9 17:23:20 | 显示全部楼层
flamma 发表于 2016-10-9 16:43
为何不行。至少我拿到个第三方库如果符合Misra-c规范,我就会觉得更安全。另外Misra-c规范除了可读性的规 ...

Misra-c规范耍流氓,指针和全局变量比goto更危险、更容易产生BUG,是不是也一并禁掉,小范围内使用goto一点危险都没有,C中有很多地方都比小范围内使用goto更容易产生BUG

出0入0汤圆

发表于 2016-10-9 17:25:37 | 显示全部楼层
takashiki 发表于 2016-10-9 17:09
符合misra的确实更安全,但他不是为资源受限的系统设置的,更不会考虑效率,主要考量还是程序健壮性。mis ...

符合misra并不会降低效率,至少ucos就是符合misra的。misra更多的目的还是减少bug发生的概率。很多时候并不是程序员水平不行,而是一时粗心产生了bug。比如有名的苹果SSL堆栈漏洞:
static OSStatus SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
                                 uint8_t *signature, UInt16 signatureLen)
{
        OSStatus        err;
        ...

        if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
                goto fail;
        if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
                goto fail;
                goto fail;
        if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
                goto fail;
        ...

fail:
        SSLFreeBuffer(&signedHashes);
        SSLFreeBuffer(&hashCtx);
        return err;
}              

在这里程序员粗心的多打了一行goto fail; 造成了SSLHashSHA1.final(&hashCtx, &hashOut)) 永远不会执行。它深嵌在连接握手的过程中,所以很难有测试用例覆盖到这个错误。如果遵循一些规范,这种错误是可能避免的。
比如:正确的缩进,if后面必须跟{},不使用goto。

出0入93汤圆

 楼主| 发表于 2016-10-9 18:22:44 | 显示全部楼层
本帖最后由 takashiki 于 2016-10-9 18:36 编辑
flamma 发表于 2016-10-9 17:25
符合misra并不会降低效率,至少ucos就是符合misra的。misra更多的目的还是减少bug发生的概率。很多时候并 ...


这个代码是真的?如果不是程序员开小差,就一定是编译器开小差了。
好的编译器一定会提示不可达代码的,至少1998年的VC6就会给出warning。
MISRA当然会降低效率,典型的就是联合体。我这是摘抄的MISRA 2004,也许您的版本更新也不一定,但是我没有。
规则 18.4 (强制):  不要使用联合。

后面又自己打脸。
实现接收和打包的代码如下:
blablabla一大堆。
不幸的是,面临可移植的实现时,大多数编译器产生的代码远非有效率的。当程序对高
执行速度和低内存使用的要求胜于移植性时,使用联合的实现是可以考虑的。
MISRA也知道不使用联合体远非有效率,为了效率考虑,强制也只好不强制了。


另外,
规则 14.4 (强制):  不应使用 goto  语句。
规则 14.5 (强制):  不应使用 continue  语句。
规则 14.6 (强制):  对任何迭代语句至多只应有一条 break  语句用于循环的结束。


请问,如果遵循MISRA C,那么do...while(0)存在的必要到底是什么?上面一堆例子全部违反规则14.6不是吗。MISRA 禁止了goto,也基本判处了do...while(0)的死刑,改成冗长的if...else更加健壮。
对于do...while(0)只有这一句描述,确实有用:
规则 19.4 (强制):  C 的宏只能扩展为用大括号括起来的初始化、常量、小括号括起来的表达式、类型限定符、存储类标识符或的宏只能扩展为用大括号括起来的初始化、常量、小括号括起来的表达式、类型限定符、存储类标识符或 do-while-zero  结构

出0入0汤圆

发表于 2016-10-9 18:36:07 | 显示全部楼层
takashiki 发表于 2016-10-9 18:22
这个代码是真的?如果不是程序员开小差,就一定是编译器开小差了。
好的编译器一定会提示不可达代码的, ...

VC6我早已不用不清楚。反正到这个bug发现时,Xcode中GCC 4.8.2版并不会报告warning,哪怕使用wall选项。

出0入93汤圆

 楼主| 发表于 2016-10-9 18:41:39 来自手机 | 显示全部楼层
flamma 发表于 2016-10-9 18:36
VC6我早已不用不清楚。反正到这个bug发现时,Xcode中GCC 4.8.2版并不会报告warning,哪怕使用wall选项。 ...

就是编译器开小差了,现在连keil都会提示不可达代码,xcode这样搞有点无语啊。

出0入0汤圆

发表于 2016-10-9 19:01:25 | 显示全部楼层
takashiki 发表于 2016-10-9 18:41
就是编译器开小差了,现在连keil都会提示不可达代码,xcode这样搞有点无语啊。 ...

现在的很多编译器确实会检查这些并警告。很多都是经过很多经验教训后才有这些警告的。不能完全依靠编译器。再拿union来说,为啥一开始会禁止union?事实有段时间,很多人都说写可移植程序的C/C++不要用union,为何?因为C++的规范里面union的内存排布是个黑洞,没有任何规定uinion应该怎么排布。理论上编译器想怎么排就怎么排,所以最经常见的一种union使用方法:

typedef struct in_addr
{
    union
    {
        struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
        struct {  u_short s_w1,s_w2; } S_un_w;
        u_long S_addr;
    }
} S_un;
} IN_ADDR;

用S_addr存入,然后用S_un_b取出。这种方法很长段时间是C语言不推荐的!因为不同的C语言编译器实现,可能得的完全不一样的结果!所以被认为没有可移植性。随着编译器的逐渐发展,大家都用这几种编译器,主流的编译器实现又基本一致。这种提法才渐渐少了。当然还要注意不同系统大小端的问题。

出0入0汤圆

发表于 2016-10-9 19:26:58 | 显示全部楼层
有时候goto也很有用,只能说尽量不要用,但在有需要的时候可以用。。

出0入93汤圆

 楼主| 发表于 2016-10-10 06:25:14 | 显示全部楼层
XIVN1987 发表于 2016-10-9 12:55
我觉得楼主这样不好!
你不喜欢用不用就好了,可你这样上来专门发个帖子说别人的代码“是一堆shit”、“恶 ...

好了,上面已经有77楼哥们祭出了MISRA C的大菜刀,基本上完全禁止了goto和do...while(0)(这个宏定义必须用无需讨论)的用法(我第90楼的引文),是不是一堆,还有哥们从可移植性和健壮性的考虑,MISRA都给出了负面看法,而且还不像联合体一样有让步的可能。现在可以说了,至少从遵循MISRA来说,除了宏定义以外,do...while(0)完全就是一堆shit,同goto完全没有两样,没有什么不能用{}+控制语句解决不了的。goto就那么一句,假如它算一坨的话,这个一大篇,所以就是一堆。
还是那一句,不能容忍goto,为什么还要用更恶心的do...while(0),纯粹脱裤子放屁。

出50入58汤圆

发表于 2016-10-10 07:52:17 来自手机 | 显示全部楼层
看了半天,终于有点明白了,do{}while(0)要和内部的break配合使用,达到快速退出的目的,和goto类似。不知道我理解的对不

出0入25汤圆

发表于 2016-10-10 08:53:27 | 显示全部楼层
takashiki 发表于 2016-10-10 06:25
好了,上面已经有77楼哥们祭出了MISRA C的大菜刀,基本上完全禁止了goto和do...while(0)(这个宏定义必须 ...


77楼只说禁goto,没说禁do-while

出0入93汤圆

 楼主| 发表于 2016-10-10 09:03:13 | 显示全部楼层
XIVN1987 发表于 2016-10-10 08:53
77楼只说禁goto,没说禁do-while

请看90楼MISRA规则14.4-14.6,不要搞双重标准。
MISRA禁止任何迭代中多个break。你说do...while(0)如果没有break,跟{}无异;如果有1个break,则相当于{}+if,if结构多清晰比这个强多了;如果有多个break,则被禁止掉了!所以说,基本算是废了。

出0入93汤圆

 楼主| 发表于 2016-10-10 09:07:11 | 显示全部楼层
鲜衣怒马 发表于 2016-10-10 07:52
看了半天,终于有点明白了,do{}while(0)要和内部的break配合使用,达到快速退出的目的,和goto类似。不知 ...

这个帖子主要就是看不惯那些有goto恐惧症非要改成do{}while(0)的膜拜者发的,你理解是对的。我个人觉得这个东西的存在价值比goto好不到哪儿去,甚至还不如goto。

出0入0汤圆

发表于 2016-10-10 10:55:44 | 显示全部楼层
还好吧,只要不是强迫症应该也没什么大问题,可能实际中有时配合break方便调试吧,我还有时用if (1) { }呢,因为有时觉得打屏蔽符号也麻烦,这样改个1或是0就好了,就像有人习惯 "1 == var"这种格式一样,个人风格问题,习惯就行
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-5-18 18:32

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

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