1515


時々こういうプログラムを見かけます

[code]

    do
    {
        if (!hoge)
            break;
        fuga();
    } while(false);
    
[/code]

これは以下のプログラムと同じではないでしょうか

[code]

    if (hoge)
    {
        fuga();
    }
    
[/code]

2つ目の書き方は1つ目の書き方よりわかりやすいしデバグしやすいと思いますが、1つ目の書き方には利点はありますか


CC BY-SA 3.0
2014-12-11T05:51:17.857
1510
2019-11-24T00:19:34.137
1077
question
c
do...while(false)の利点は何ですか


実際のコードをみていないので、上のコードをみてのイメージです。

  1. `hoge` の処理の前に`hoge` と `fuga` に関連するような処理かつ、`hoge` の実行前に行いたい処理がある場合に一連の意味的なかたまりを同じブロックに入れて、わかりやすくするような場合もありそうと思いました。

  2. C言語などではマクロで展開されることを考慮して最初の書き方をよくしているイメージがあります。 ref. <https://www.jpcert.or.jp/sc-rules/c-pre10-c.html>


CC BY-SA 3.0
2014-12-11T06:08:10.277
1511
2014-12-11T06:08:10.277
982
1510
answer


do~while文はそもそも「1度はまわす」という前提条件があると認識してるので、あまり利点がないような・・
私もごく稀にみますが、そもそもdo~whileで書いてたところに例外処理が後から加わったのかなーとか勝手に思ってたり。

強いていうなれば、do内の結果がやってみないと分からない場合
(たとえば、冪乗計算の計算結果だとわかっている数値があるが、それが何の冪乗なのかを調べる、など) においては、あり得るのかもしれないです。
どちらにしても、ifとdo~whileの使い分けが出来てないってことになるのかもしれませんが。


CC BY-SA 3.0
2014-12-11T06:12:21.910
1512
2014-12-11T06:12:21.910
905
1510
answer


質問に書かれているコードそのままだと do-while を用いるメリットはあまり無さそうですが、例えば「`fuga()`を実行するためには
`hoge1()` 〜 `hoge3()`
の全てに成功している必要がある」というようなケースだと利点があるように思えます。元のコードを見ていないので憶測となりますが、後々に`fuga()`を実行するための条件が増えることを考慮し、あらかじめ
do-while で囲っているのかもしれません。

[code]

    /* do-while 版 */
    do {
        if (!hoge1())
            break;
        if (!hoge2())
            break;
        if (!hoge3())
            break;
        fuga();
    } while(0);
    foobar();
    
    /* if 版 */
    if (hoge1()) {
        if (hoge2()) {
            if (hoge3()) {
                fuga();
            }
        }
    }
    foobar();
    
[/code]

goto 文が禁止されていたり使わない信条だったりすると、代用として do {} while(0) を使って書かれることもあるのかなと思います。


CC BY-SA 3.0
2014-12-11T07:05:04.643
1515
2014-12-11T07:05:04.643
1024
1510
answer


もちろん褒められた書き方ではありませんが、一般化して 「swtich で break を書かないケースの逆版」
と考えると、多少は納得ができるのではないでしょうか。

[code]

    switch (n) {
      case 1:
        doA();
      case 2:
        doB();
      default:
        doC();
    }
    
[/code]

nが1の時には doA, doB, doC を実行し、2の時はdoBと doC だけを実行しています。 doA, doB, doC
はこの順序で実行しなければならないとした場合、 この逆(?)版では 1のときはdoA だけを、2のときは doAとdoBを実行することになります。 それは
do while(0) を使ってこのように書けますよね。

[code]

    do {
      doA();
      if (n == 1) break;
      doB();
      if (n == 2) break;
      doC();
    } while (0)
    
[/code]


CC BY-SA 3.0
2014-12-11T07:41:08.613
1517
2014-12-11T07:41:08.613
208
1510
answer


# diff に優しい

バージョン管理システムやパッチを当てる時に些細なコンフリクトを避けられる場合があります。

例えば条件文に`hoge2()`と`hoge3()`を追加する変更が同時に起こると、 以下のようなコンフリクトが起きます:

[code]

    diff --cc test.c
    index 910e21d,b24c790..0000000
    --- a/test.c
    +++ b/test.c
    @@@ -1,4 -1,4 +1,10 @@@
    ++<<<<<<< HEAD
     +if (hoge() && hoge3())
    ++||||||| merged common ancestors
    ++if (hoge())
    ++=======
    + if (hoge() && hoge2())
    ++>>>>>>> conf
      {
          fuga();
      }
    
[/code]

これに比べ`do ~ while`を使った場合は行単位の意味付けが強くなるので、マージが気楽です。

[code]

    diff --cc test.c
    index e138846,9469263..78dffc5
    --- a/test.c
    +++ b/test.c
    @@@ -1,8 -1,8 +1,10 @@@
      do
      {
    +     if (!hoge2())
    +         break;
          if (!hoge)
              break;
     +    if (!hoge3)
     +        break;
          fuga();
      } while(0);
    
[/code]

考えたくも無いですが、if文が大量にネストしていると前者は更に悪夢です。
条件を消すだけでインデントは崩れ、それを直すだけのコミットが混じり、後から条件の一部分だけ巻き戻すような処理も一苦労です。


CC BY-SA 3.0
2014-12-11T10:30:17.103
1525
2014-12-11T10:30:17.103
62
1510
answer


単純に、ブロックを作りたいだけなんじゃないでしょうか。

[code]

    {
        ...
    } 
    
[/code]

という書き方を知らなくて

[code]

    do {
        ...
    } while (0);
    
[/code]

と書いているのかも。


CC BY-SA 3.0
2014-12-16T23:39:51.073
1826
2014-12-16T23:39:51.073
4199
1510
answer


`#define` でマクロをこの記法で書くと末尾に セミコロンがつけられます。

[code]

    #define my_max(a,b) do{((a)>(b))?(a):(b)}while(0)
    my_max(1, 2);
    
[/code]


CC BY-SA 3.0
2015-08-22T10:44:41.707
14729
2015-08-22T12:25:16.783
2015-08-22T12:25:16.783
8000
4727
1510
answer


100害あってほぼ1利なしのコードです。  
何が何でも理由があってもgotoを認めない  
というコーディング規約があるところで  
時折見かけるコードです。  
そういうとき、例外処理のようなことをやろうとすると、  
その代わりの方法として関数分割して  
途中でreturn(これすら禁止されている場合もある)するか  
上記のように`do { ... } while (0)`で  
囲ってあげてツールでの規約違反チェック等を避けるのに使います。  
あとは、有用な例の一つとしては  
既に挙げられているマクロでの利用でしょうか。  
ただし、これは……個人的にあまり好きではありません。

[code]

    #include <stdio.h>
    
    #define HOGE_FUNC(A,B) do { \
        if (A > B) { \
            printf("%d is bigger than %d", A, B); \
        } \
        else { \
            printf("%d is bigger than %d", B, A); \
        } \
    } while (0)
    
    
    int main() {
        int a = 10;
        int b = 3;
        int condition = 1;
    
        if (condition)
            HOGE_FUNC(a,b);
        else
            puts("else");
    
        return 0;
    }
    
[/code]

何故なら`do { ... } while(0)`でマクロを囲まなくても  
`if`と`else`で必ず  
`{ ... }`で囲うことを徹底すれば問題になりませんので。


CC BY-SA 3.0
2015-08-22T16:58:42.247
14740
2015-08-22T17:03:54.770
2015-08-22T17:03:54.770
7744
7744
1510
answer


# do…while(0)の利点

  * 複雑な条件のif文を書きたくない、レビューしたくない。  
単純な条件のif文を連ねた方がロジックを理解するのが簡単

  * ブロックを抜けるとき`goto`文を使いたくない。とび先のラベルをレビューするのが面倒

以下はおまけです。質問の趣旨から外れています。

# `goto`文を使わない理由

小規模なプロジェクトやプライベートでは`goto`の使用が適切な場合があると考えますが、大規模なプロジェクトでは`goto`が禁止されることが多々あります。※契約上使えない

多人数で開発する場合、メンバの平均スキルはどうしても低くなります。  
低いスキルに合わせるには`goto`文の禁止もやむ無しと考えます。  
多重のブロック内から一気にbreakしたいとき`goto`文を使いたくなりますが、レビューをする側から`goto`を見つけるたびに妥当性を確認するのはコスト増につながります。

背景がわからないと、「何がよいプルグラムか」を私は判断できません。


CC BY-SA 4.0
2019-11-24T00:19:34.137
60795
2019-11-24T00:19:34.137
35558
1510
answer