よりよいソースコードはどっち?

[戻る]
まに 2008/10/22(水) 23:07:43
皆さんに質問なのですが、「よりよいソースコード」、
すなわち、「可読性・保守性に優れたソースコード」とは、
どのようなソースコードだと思いますか?


私には、自分なりのプログラミングスタイルというものがあり、
それが自分にとっても万人にとっても見やすいと思っています。
しかし、会社では私のスタイルは受け入れてもらえず、
会社の定めた規則に従ってプログラミングしていました。
その規則とは、次のようなものです。

・if文には必ず{}をつけろ
・マルチステートメントにするな
・goto文、continue文は使うな
・比較演算子の「>」は使うな
・ソースコードの右側にコメントを記述するな

対して、自分は、以下のようなスタイルを持っています。

・if文の{}は、前後とのバランスなどに応じて、つけたりつけなかったり。
・似た処理が続く場合は、マルチステートメントにする(特にswitch文のcase処理)。
・不必要にネストが深くなるのを避けるために、continue文を使う。
・例外処理を簡潔化するため、場合によってはgoto文も使用。
・変数と数値を比較するときは、変数を必ず左側に書く。
・ソースを左側、コメントを右側と分けることで、印刷時の可読性を向上。


特に、最大の違いは、行数です。
会社の規則に従うと、縦に間延びしたソースコードとなり、
スクロールしないと全体を見渡せません。

対して、自分は
「1行には『1つの意味』を持つコードを記述」
することを心掛けています。

以下に、会社の規則に従って記述した「ソースコードA」と、
自分流のスタイルで記述した「ソースコードB」を書き込みさせていただきました。
皆さんは、どちらのソースコードがよりよいと思いますか?
率直なご意見をお聞かせいただければ幸いです。

まに 2008/10/22(水) 23:07:59
■ ソースコードA:会社の規則スタイル ■

001|#include "stdafx.h"
002|
003|#define    DATASIZE     8
004|#define    DATAMAX      256
005|
006|bool    Function(void)
007|{
008|    FILE    *fp;
009|    char    *Buf;
010|    int     Op, No1, No2, Ans;
011|    int     Cnt1, Cnt2, ErrCnt;
012|    int     i, v;
013|
014|
015|    ////// メモリ確保/ファイルオープン(処理a)
016|
017|    Cnt1 = Cnt2 = ErrCnt = 0;
018|
019|    // メモリ確保
020|    if ((Buf=(char*)malloc(DATAMAX*DATASIZE)) == NULL) {
021|        return FALSE;
022|    }
023|        
024|    // ファイル有無チェック
025|    if (FileExist("file.dat") == FALSE) {
026|        free(Buf);
027|        return FALSE;
028|    }
029|
030|    // ファイルオープン
031|    if ((fp=fopen("file.dat","rb")) == NULL) {
032|        free(Buf);
033|        return FALSE;
034|    }
035|
036|    // ファイル読み込み
037|    if (fread(Buf, DATASIZE, DATAMAX, fp) < DATAMAX) {
038|        fclose(fp);
039|        free(Buf);
040|        return FALSE;
041|    }
042|
043|    ////// メイン処理(処理b)
044|
045|    for (i=0; i<DATAMAX; i++) {
046|
047|        ////// 演算子、数値1,2取得(処理c)
048|        if (DataGet(Buf, i, &Op,&No1,&No2) == FALSE) {
049|            fclose(fp);
050|            free(Buf);
051|            return FALSE;
052|        }
053|
054|        ////// データによる処理の分岐(処理d)
055|
056|        // データ読み飛ばしでないなら処理を実施
057|        if (Op != 0) {
058|
059|            // 0除算チェック
060|            if ((Op != '/' && Op != '%') || No2 != 0) {
061|
062|                // 数値1,2ともに正ならCnt1加算
063|                if (0 < No1 && 0 < No2) {
064|                    Cnt1++;
065|                }
066|                // 数値1,2ともに正でないならCnt2加算
067|                else {
068|                    Cnt2++;
069|                }
070|
071|                ////// 演算処理(処理e)
072|                switch (Op) {
073|                    case  '+':
074|                        Ans = No1 + No2;
075|                        break;
076|                    case  '-':
077|                        Ans = No1 - No2;
078|                        break;
079|                    case  '*':
080|                        Ans = No1 * No2;
081|                        break;
082|                    case  '/':
083|                        Ans = No1 / No2;
084|                        break;
085|                    case  '%':
086|                        Ans = No1 % No2;
087|                        break;
088|                }
089|
090|                ////// 結果表示(処理f)
091|                if (AnsPut(i, Ans) == FALSE) {
092|                    fclose(fp);
093|                    free(Buf);
094|                    return FALSE;
095|                }
096|
097|                ////// その他の処理(処理g)
098|
099|                DataGetMaking(Buf, i, &v);
100|                if (v) {
101|                    DataSetMaking(v, Ans, 300, 128);
102|                }
103|
104|                DataGetComp(Buf, i, &v);
105|                if (v) {
106|                    DataSetComp(v, No1, 210, 85);
107|                }
108|
109|                DataGetAdjust(Buf, i, &v);
110|                if (v) {
111|                    DataSetAdjust(v, No2, 108, 255);
112|                }
113|
114|                DataGetCheck(Buf, i, &v);
115|                if (v) {
116|                    DataSetCheck(v, Op, 153, 32);
117|                }
118|
119|                DataGetListUp(Buf, i, &v);
120|                if (v) {
121|                    DataSetListUp(v, 0, 4, 11);
122|                }
123|
124|            }
125|            else {
126|                ErrCnt++;
127|            }
128|        }
129|
130|    }
131|
132|    ////// 後処理(処理h)
133|    if (KekkaSyori(fp, Cnt1, Cnt2, ErrCnt) == FALSE) {
134|        fclose(fp);
135|        free(Buf);
136|        return FALSE;
137|    }
138|
139|    fclose(fp);
140|    free(Buf);
141|    return TRUE;
142|}

まに 2008/10/22(水) 23:08:11
■ ソースコードB:自分流スタイル ■
(本来は、ソースコードの右側にコメントがあるのですが、
折り返し発生防止のため割愛してあります)

01|#include "stdafx.h"
02|
03|#define    DATASIZE        8
04|#define    DATAMAX         256
05|#define    FileClose(a)    if (a!=NULL) { fclose(a);a=NULL; }
06|#define    MemFree(a)      if (a!=NULL) { free(a);a=NULL; }
07|
08|bool    Function(void)
09|{
10|    FILE    *fp = NULL;
11|    char    *Buf = NULL;
12|    int     Op, No1, No2, Ans;
13|    int     Cnt1, Cnt2, ErrCnt;
14|    int     i, v;
15|
16|    // メモリ確保/ファイルオープン(処理a)
17|    Cnt1 = Cnt2 = ErrCnt = 0;
18|    if ((Buf=(char*)malloc(DATAMAX*DATASIZE)) == NULL)    goto ErrEnd;
19|    if (FileExist("file.dat")                 == FALSE)   goto ErrEnd;
20|    if ((fp=fopen("file.dat","rb"))           == NULL)    goto ErrEnd;
21|    if (fread(Buf, DATASIZE, DATAMAX, fp) < DATAMAX)      goto ErrEnd;
22|
23|    // メイン処理(処理b)
24|    for (i=0; i<DATAMAX; i++) {
25|
26|        // 演算子、数値1,2取得(処理c)
27|        if (DataGet(Buf, i, &Op,&No1,&No2) == FALSE)      goto ErrEnd;
28|
29|        // データによる処理の分岐(処理d)
30|        if      (Op==0)                    { continue; }
31|        else if (Op=='/' && No2==0)        { ErrCnt++; continue; }
32|        else if (Op=='%' && No2==0)        { ErrCnt++; continue; }
33|        else if (No1 > 0 && No2 > 0)       { Cnt1++; }
34|        else                               { Cnt2++; }
35|
36|        // 演算処理(処理e)
37|        switch (Op) {
38|        case '+':  Ans = No1 + No2;    break;
39|        case '-':  Ans = No1 - No2;    break;
40|        case '*':  Ans = No1 * No2;    break;
41|        case '/':  Ans = No1 / No2;    break;
42|        case '%':  Ans = No1 % No2;    break;
43|        }
44|
45|        // 結果表示(処理f)
46|        if (AnsPut(i, Ans) == FALSE)    goto ErrEnd;
47|
48|        // その他の処理(処理g)
49|        DataGetMaking(Buf, i, &v); if (v) DataSetMaking(v, Ans, 300, 128);
50|        DataGetComp  (Buf, i, &v); if (v) DataSetComp  (v, No1, 210,  85);
51|        DataGetAdjust(Buf, i, &v); if (v) DataSetAdjust(v, No2, 108, 255);
52|        DataGetCheck (Buf, i, &v); if (v) DataSetCheck (v,  Op, 153,  32);
53|        DataGetListUp(Buf, i, &v); if (v) DataSetListUp(v,   0,   4,  11);
54|
55|    }
56|
57|    // 後処理(処理h)
58|    if (KekkaSyori(fp, Buf, Cnt1, Cnt2, ErrCnt) == FALSE) goto ErrEnd;
59|
60|    FileClose(fp);
61|    MemFree(Buf);
62|    return TRUE;
63|
64|ErrEnd:
65|    // エラー発生時処理(処理i)
66|    FileClose(fp);
67|    MemFree(Buf);
68|    return FALSE;
69|}

SH 2008/10/22(水) 23:49:55
> DataGetMaking(Buf, i, &v); if (v) DataSetMaking(v, Ans, 300, 128);

1行に複数の命令を入れるのは避けてもらいたところです。
デバッグ時に追いづらくなるので。

wood 2008/10/23(木) 07:22:11
ソースコード2

if ((Buf=(char*)malloc(DATAMAX*DATASIZE)) == NULL)    goto ErrEnd;
確保できていないメモリ解放に行きますよね
コード1ならなにもせづ戻るのだから問題少ないよね
呼び出し元にエラーコード返したいよね
どんなコードまで処理して戻ってきたのか?

if (FileExist("file.dat")                 == FALSE)   goto ErrEnd;
ファイルオープンしていない、ファイルポインタをクローズしに行こうとしますよね


エラー処理が、エラー誘発コードになるのは避けたいですね


共通
Cnt1 = Cnt2 = ErrCnt = 0;

他言語的考え方では好ましくありません
Cnt1  = 0;
Cnt2  = 0;
ErrCnt = 0;

必ず実数を明示代入させます
アドレスが代入されるバグを減らすためです

wclrp ( 'o') 2008/10/23(木) 07:54:22
よのなかいろいろと変な規則は存在するね。
面倒な思いするならgoto使ってもいいんじゃね?っとか。

・if文には必ず{}をつけろ
賛成
ソース修正とかブレークポイント置くとか考えると
1行にif((r = func()) == v) a = b;というのは好まない。

・goto文、continue文は使うな
gotoは使わないに越したことないと思うが強制はないな。
continue使わないとかかえってへんなコード書くことになるだろ
あたま悪い奴が自分のために考えたルールだな?

・比較演算子の「>」は使うな
あたま悪い奴が自分のために考えたルール?

・ソースコードの右側にコメントを記述するな
?

>会社の規則に従うと、縦に間延びしたソースコードとなり、
俺はこれよりさらに縦伸び派


可読性をあげるためのルールが
やがてルールを守れとかルールを守らないお前が気に入らないって話になって
可読性を下げてまでルールを守るというおかしなことはよくあるよね。


総合的にみると俺は会社のルールの方がいいと思う。
部分的にみると会社のルールに気に入らないものがある。

受け入れないとは細かくルールでなおさせられるってことか。
多少は直した方がいいと思う。
おれは細かくルール強制はしない。
だって俺がその時その時気分的に書きやすく書くアバウトだから。


Functionの前に
// FALSE エラー
とか書いてないのが気になる。
常識的にエラーはFALSEだろみたいなのはあるかもしれないけれど。

すぐ下のmallocでわかるから
// メモリ確保
ってコメント必要?

俺の今の好みはswitch caseは同じインデント。
switchのないcaseなんてないし
複数のswitch caseが連続している場合を除けばれば
caseの上の行を見ればすぐにswitchを見つけられるし
無駄に左に空白があいて横スクロールが必要になる。

C/C++にtry finallyがあればgoto ErrEndなんていらないのにね。

やじうま 2008/10/23(木) 07:58:41
独断と偏見でいえば
私にとってはソースコードAのほうがよい
ソースコードB 読む気もしない
ひょっとしたら ひとりよがりの考えに凝り固まって
いらっしゃるのではないでしょうか

ばりばり 2008/10/23(木) 08:10:44
ぱーっとみたところ
ソースコードA のほうがよみやすい ソースコードB のほうはつかれる
ただし会社規則ってやつの

・goto文、continue文は使うな
・比較演算子の「>」は使うな
・ソースコードの右側にコメントを記述するな

なんじゃこれ?って感じ

PATIO 2008/10/23(木) 10:41:40
他の人とほぼ同じで基本的にはAの方が見やすいです。

・if文には必ず{}をつけろ
他の方も言われていますが、デバッガで追う時のことを
考えるとこっちの方がステップ・バイ・ステップで
追えるので有利です。

・goto文、continue文は使うな
gotoはともかく、continueに関しては反対ですね。
かえって読みにくくなります。
あと、gotoに関しては使った方がリーズナブルであれば、
良いかなと考えています。特に逆戻りしないgotoならば。
但し、gotoを使うことでバグを誘発するようなコードに
なるなら使うべきじゃないです。
どうしても使わざる得ない時だけですね。

・比較演算子の「>」は使うな
・ソースコードの右側にコメントを記述するな
この二つに関しては意味不明ですね。
理由がきちんと説明されていれば、そういう意味かと思えるかもしれませんが。
まあ、コメントの入れ方に関しては色々有りそうなので
ここに書かれている内容だけでは何とも言いかねます。

で、個人に取って読みやすいソースが万人にとって読みやすいかは
かなり難しい話なのでこれなら誰が読んでも解りやすいと言うのは
難しいかなと思います。これだと大半の人は読みやすいと言うのなら
ありえそうですけれど。
会社のコーディングルールは画一化することでソースによって見方を
変える必要はなくなると言う意味では有用です。
なので、リーズナブルな理由があるのであれば採用されてしかるべきですし、
逆に意味不明なものなら意味があるものに変更するのは一向に構わないと
思います。この辺はコーディング規約の改正が出来るかどうかと言う話に
なりますね。
但し、改訂するにしても万能のコーディングルールと言うのは多分ありえない
と思うので柔軟な発想が必要だと思います。

PATIO 2008/10/23(木) 10:44:43
追記

・マルチステートメントにするな
一般的にマルチステートメントは可読性が落ちるので
止めましょうと言うのが多いと思いますよ。
あとは、トリッキーなソースより素直な記述が良いとか
ありますね。
ソースをメンテナンスする人材がいつもベテランとは限りませんから
不必要にソースを難解にするのはメンテナンス性を落とす事になります。

Ban 2008/10/23(木) 10:48:26
> C/C++にtry finallyがあればgoto ErrEndなんていらないのにね。

C++ならデストラクタあるので、個人的にはfinallyはなくてもいいのですが、
Cは…許されるならばもう書きたくない…

というか、bool使ってるのはCでなくC++なんでしょうか。(afx…だとC99ではなさそう?)
であれば、mallocして各returnでfreeとかやってる時点で「ない」なぁ。>どっちも
と言うのが率直な感想です。


実は別に「(C++なのに)例外処理禁止」とかいう謎ルールがあったりするとか。
# でも、こういうルール作るC言語屋さんに限って、
# MFCとか使うのにCExceptionとか考えてなかったり、
# ひどいところになると、catchすら許してくれなくて「何それ?」とかいいそう…。

2008/10/23(木) 11:28:53
此処には触れて無さそうだけど…
>003|#define    DATASIZE     8
>004|#define    DATAMAX      256

#define    DATASIZE     (8)
#define    DATAMAX      (256)
と、自分は括弧を意図的につける様にしています。

(例えば…)
#define    DATA1     8
#define    DATA2     DATA1 - 1
#define    DATAALL   DATA1 * DATA2

この時()をつけるか否かで異なる値になります。

仲澤@失業者 2008/10/23(木) 11:51:04
1.まず、A、B共に十分見やすいコードだと思います。
  次に、可読性、保守性は、それを見る人の能力や、
  使用するツールによるので何とも言えません。

2.コーディングルールは、多分今後は意味がなくなるので、あまり
  気にしすぎる必要は無いように思います。

今は、VC2008のエディタ等の様に、コメント、関数本体、
引数等の表示非表示の選択機能ぐらい付いて無いと
ダルくてやってられません。単純なテキストエディタなどは
もう、長い間使ってません。

おそらく今後は、この様な専用コーディングツール化の方向に
進んでいくと想像でき、コード時のスタイルと、テキストへの
出力時のスタイルの分離が進むのでしょう。

ですから、あまりスタイルなどに気をとられずに、良い仕組み
の創造に注力していったほうが良いと考えます。
「いずれ意味の無くなることに気をとられるな」ということです。

bun 2008/10/23(木) 11:59:51
まぁ個人的な意見言い出したらきりがないですが、
基本的にコーディング規約というのは、「みんなで同じにすると他人のコードが読み
やすいですよ」というものなので、決めごとでしかないなら、上司の言うとおりにす
るというのが私の姿勢です。

その視点で見ると、以下の3つは決めごとなので従えばよいのではないでしょうか。
  ・if文には必ず{}をつけろ
  ・マルチステートメントにするな
  ・ソースコードの右側にコメントを記述するな

以下のやつは意味不明。
  ・比較演算子の「>」は使うな
不等号の向きを全社統一しようという試みでしょうか?そういうことなら決めごとに
すぎないので、やはり従えばよいと思います。

以下のやつだけ反対です。
  ・goto文、continue文は使うな
これは決めごとではないからです。goto文、continue文を使わないと、ソースコード
の構造が変わります。しかも、本当にgoto文、continue文が有効な場面では、汚い方
へ構造が変わるからです。

rin 2008/10/23(木) 12:19:19
私もAが見やすい

そのソース・仕事内容を知ってる人ならBのほうが見やすいが
Aなら、まったく知らない人でも、慣れた人でも大差なく見れる
って思います

>「1行には『1つの意味』を持つコードを記述」
Aは、コンピュータの処理が一行に一つの意味
Bは、プログラマーがやらせたい処理が一行に一つの意味
という感じになってますな
最初に書きましたが、
やらせたい処理が見る人に伝わってるならBのほうがいいが
そうでないなら
「一行分のやらせたいこと」を把握する必要がある分やっかいかと

>・比較演算子の「>」は使うな
たとえば
x > 0 && x < 10 より
0 < x && x < 10 のほうがやらせたいことがわかりやすいとかかな

PATIO 2008/10/23(木) 13:08:43
>> ・比較演算子の「>」は使うな
> たとえば
> x > 0 && x < 10 より
> 0 < x && x < 10 のほうがやらせたいことがわかりやすいとかかな

こういう例があれば、どういう事を意図して決めたのかが
わかるので、それが納得できる内容ならそれはそれかなと思います。

結局、私も

「基本的にコーディング規約というのは、「みんなで同じにすると他人のコードが読み
やすいですよ」というものなので、決めごとでしかないなら、上司の言うとおりにす
るというのが私の姿勢です。」

に賛成です。
一人でコードを書く場合と違って、会社ではチームとしてのメンテナンス性を
要求されます。なので、やはりチームのルールとして定められているなら
従うしかないかなと思います。
まあ、皆が納得できるだけの理由を挙げれば一部変更することは可能かもしれませんけど。

PATIO 2008/10/23(木) 13:13:03
> #define    DATAMAX      (256)
> と、自分は括弧を意図的につける様にしています。

御意。
これってC言語では特に利いてきますよね。
これをやっていなかったばかりに意味不明なバグに悩まされたりする事もありえるので。
C++だとconstで定数化する事が多いので#defineは条件コンパイルの時くらいしか
使いませんけれど。

FUKU 2008/10/23(木) 13:14:13
私個人の考えです。

・if文には必ず{}をつけろ
 賛成
・マルチステートメントにするな
 賛成。
・goto文、continue文は使うな
 反対
・比較演算子の「>」は使うな
 反対 (というか意味不明)
・ソースコードの右側にコメントを記述するな
 基本的に賛成だけど場合によりけり

maru 2008/10/23(木) 15:11:06
規則は暗黙的に守ることより、なぜその規則があるかを理解して守る必要があるでしょう。
当然、規則の目的がおかしなものであれば改善すべきだし、必要なら遵守しなければならない
でしょう。
ただ単に規則だからといって強制されていると、その真の目的を忘れておかしなコードを書い
てしまうこともあり得ます。そのためには規則を逸脱する手段が必要でしょう。例えばコード
レビューで承認を得る、等の。こういう逸脱手順なしで規則を運用されると私としてはかなり
息苦しいことになります。

提示されている規則そのものに関しては、
> ・if文には必ず{}をつけろ
賛成
> ・マルチステートメントにするな
賛成
> ・goto文、continue文は使うな
基本的には賛成。ただし逸脱してもよい(逸脱手順が必要)
> ・比較演算子の「>」は使うな
どちらでも良い。
# 最初は意味が分からなかった。
> ・ソースコードの右側にコメントを記述するな
反対。(意図が分かれば賛成するかも。)

コメントに関しては余計なコメントは邪魔になるだけなので、なるべくコメントなしで読める
ソースにしろ、と指導しています。(ファイルヘッダ、関数ヘッダは付けます。)
コメントは結果的に嘘になってしまうことがあり(コードを修正してコメントは修正を忘れる)
、人のソースを読む場合、あまりコメントは信用していません。

aetos 2008/10/23(木) 15:17:24
どっちが読みやすいかと言えば前者。

以下、俺のポリシー。

> ・if文には必ず{}をつけろ
賛成。
加えて、{} だけで1行使え。
ただし else if の場合の else に個別に {} をつける必要はない。

> ・マルチステートメントにするな
賛成。

> ・goto文、continue文は使うな
goto はわかって使っているのであれば許可。continue は許可。
でも goto を使わざるをえないような言語は使いたくない。

> ・比較演算子の「>」は使うな
別にいいじゃん?

> ・ソースコードの右側にコメントを記述するな
別にいいじゃん?

h 2008/10/23(木) 15:40:22
>それが自分にとっても万人にとっても見やすいと思っています。
そう思っているのはあなただけ。
どんなベテランが書こうが「万人にとっても見やすい」
なんてありえません。

んで私の意見

> ・if文には必ず{}をつけろ
賛成。

> ・マルチステートメントにするな
賛成。

> ・goto文、continue文は使うな
gotoは賛成(場合によりけり)
continueは反対

> ・比較演算子の「>」は使うな
反対(というか普通に使う)

> ・ソースコードの右側にコメントを記述するな
どっちでもいいけど私的には賛成

maru 2008/10/23(木) 17:55:53
>此処には触れて無さそうだけど…
>>003|#define    DATASIZE     8
>>004|#define    DATAMAX      256

良く見たら他にも問題のあるマクロもありますね。
>05|#define    FileClose(a)    if (a!=NULL) { fclose(a);a=NULL; }
>06|#define    MemFree(a)      if (a!=NULL) { free(a);a=NULL; }

ITO 2008/10/23(木) 20:07:37
社内で協力しあってソフトを作る以上、規制は必要です。
やはり、Aのほうが見やすいですね。

>・if文には必ず{}をつけろ
 

>・マルチステートメントにするな

>・goto文、continue文は使うな

>・比較演算子の「>」は使うな

>・ソースコードの右側にコメントを記述するな

ITO 2008/10/23(木) 20:27:01
すみません、
途中で切れたので最初から書きました。
-------------------------------------------------------------

社内で協力しあってソフトを作る以上、規制は必要です。
やはり、Aのほうが見やすいですね。
Bだとすぐ分からないですよね。

>・if文には必ず{}をつけろ
 賛成
  if文が幾つも重なった時、分かりにくい。 

>・マルチステートメントにするな
 賛成
 これも、多くなった時分かりにくい。

>・goto文、continue文は使うな
 ontinue文は必要だと思う。
  goto文は、こうかな。
 「goto文は原則的に使ってはいけない。
 ただし、必要の場合で開発チームのリーダの了解が
 取れた時のみ使用を許可する。」
 goto文を使うと意図しない動作になってしまうことが多い。
 本人が気づいてなくて問題になることもあると思う。
 なれないうちはいやでも周囲の了解を得たほうがいいと思う。

>・比較演算子の「>」は使うな
 反対、
 ただ一言いうなら、「=」、「==」、「<」と判別で生きるように書く。
 かな
 

>・ソースコードの右側にコメントを記述するな
 1行何文字で(印刷、表示か)だと思う。
 紙の端までコメントが続いたら見づらいよね。

以上です。

 

たいちう 2008/10/23(木) 21:19:10
> 私には、自分なりのプログラミングスタイルというものがあり、
> それが自分にとっても万人にとっても見やすいと思っています。
> しかし、会社では私のスタイルは受け入れてもらえず、

ここが既に矛盾してますよね。
あなたのスタイルが万人にとっても見やすいならば、
会社の人たちにとっても見やすいはずでしょ。
会社の人たちも見やすいと感じているのに受け入れられない事情があるなら、
こんなところで意見を聞いても意味が無いし。

他の多くの意見と同様、私もソースコードAの方が読みやすく感じます。
以下はあなたのルールについての私の意見ね。


> ・if文の{}は、前後とのバランスなどに応じて、つけたりつけなかったり。

私は、1行だけの場合は{}でくくりませんが、{}を付けるスタイルを
否定するものではない。

> ・似た処理が続く場合は、マルチステートメントにする(特にswitch文のcase処理)。

私も処理eのようなswitchを書くこともあるけど、
処理dや処理gはやりすぎだと思う。

> ・不必要にネストが深くなるのを避けるために、continue文を使う。

これには賛成。でもソースコードAが不必要にネストが深くなっているとは思わない。
これはcontinueの必要性を訴えるほどの例ではないですね。

> ・例外処理を簡潔化するため、場合によってはgoto文も使用。

これもルールとしては賛成だけど、ソースコードAもそれなりに簡潔と思う。
gotoでまとめるにしても、FileClose(a)とMemFree(a)のマクロは無い方がいいと思う。

> ・変数と数値を比較するときは、変数を必ず左側に書く。

反対。『比較演算子の「>」は使うな』と同じくらいナンセンス。

> ・ソースを左側、コメントを右側と分けることで、印刷時の可読性を向上。

これは消極的に反対。印刷時のことはそれこそ環境依存。
どんなプリンタを使っていて、どんな用紙にどんなフォントで何の目的で
印刷するのか分からないので、ここでの議論は無意味だと思うな。
『皆さんはどういうときにどのように印刷してますか?』っていう質問なら別だけど。
コーディングスタイルとしては、一行の文字数が長くなりすぎになるかも、
ということで、消極的に反対。


最後に、戻り値の型がboolなのに、TRUEやFALSEを返しているのはどうかと。
(良く知らんけどC99に準拠?)

まに 2008/10/23(木) 22:31:13
[[解決]]
皆さん、ご意見ありがとうございました。
まとめると、
「ソースコードAの方が見やすい。ただし、会社規則にも疑問な部分がある」
といったご意見が、多数派のようですね。

でも、ソースコードB、そんなに見ずらいかなぁ…。
「縦に長く書くか、横に詰めて書くか」が大きく違うだけで、
全体的なコード量はほぼ同じなんですけどね…。
スクロールしないと全体を見渡せないよりも、
パッと見はゴチャゴチャ感があっても全体を一望できる方が、
解析する分には好きなんだけどなぁ…。
でもそれが「万人に共通」と思っていたのは、
どうやら自分の思い込みだったみたいで…。


> ・if文には必ず{}をつけろ
自分の場合、
「一連のif 〜 else if 〜 elseの中で、
一つでも{}が必要なら、すべて付ける。
そうでなければつけない」
というスタイルを取っています。
基本的にはつけない方がスッキリするので。
でも、「必ず付ける」と徹底した方が、間違いないですね。

> ・マルチステートメントにするな
デバッガで追う時は自分も不便さを感じることがあります。
しかし、処理gのように、引数の違いが目に飛び込んでくるので、
マルチステートメントも捨てがたいんですよね…。

> ・goto文、continue文は使うな
「continue文やgoto文を使うと分かりづらくなる」
という話をよく耳にしますが、それは使い方次第だと思うんですよね。
ソースコードBでは、異常時の処理を「goto ErrEnd」で統一化することで、
「free,fcloseを気にする必要がない」という利点があります。
なのに、会社では「gotoは論外!」と怒られたことがあります。

> ・比較演算子の「>」は使うな
おそらくrinさんのおっしゃる理由で定められたルールだと思います。
でも自分は、変数が左側の方が直観的なんです。
「3 < a」とかを言葉にすると、「3がaより小さかったら」なんてなっちゃうので。

> ・ソースコードの右側にコメントを記述するな
複数人数でプログラミングしてますから、「コメントの書き方も統一しましょう」ってこ
とだと思います。
コメントの文面までルール化されていて、「句読点を使うな」と言われたこともありま
す。


ルールにも、理由があるならいいけど、
理由がない(もしくは理由が間違ってる)ルールは、ほんと、やめてほしいです。
そういえば、別の会社ですが、次のようなルールを定めてる会社もありました。
・数値の値によって分岐する場合は、分岐が4つ以上ならswitch文、4つ未満ならif文を使
え。
・関数の引数は、4つ以内にしろ。それを超える場合は、構造体にして渡せ。
このルールの必要性も、未だ不明です。

あと、defineのカッコについてですが、自分は、
「#define    DATA1     8」の場合はカッコを付けませんが、
「#define    DATA2     DATA1 - 1」の場合はカッコを付けます。
であれば、問題ないですよね…?
「#define    FileClose(a)    if (a!=NULL) { fclose(a);a=NULL; }」は、
「#define    FileClose(a)    do { if (a!=NULL) { fclose(a);a=NULL; } } while
(0)」と
書くべきってことか…。


とりあえず、「会社では会社規則に従う。趣味では自分流」という、
今まで通りのスタンスで行こうと思います。
でも「自分流のスタイルが他の人には見ずらい」ということが分かって、良かったです。
趣味でも、あまり自分流に突っ走りすぎないよう、気を付けます。
皆さん、どうもありがとうございました。

SH 2008/10/23(木) 23:37:13
> ・関数の引数は、4つ以内にしろ。それを超える場合は、構造体にして渡せ。
> このルールの必要性も、未だ不明です。

環境が違うとは思いますが、
Windowsパソコンではない別のハードでやってた頃は言われてました。
そのハードの機能上の制限によるものでしたが。

2008/10/24(金) 00:14:32
> あと、defineのカッコについてですが、自分は、
> 「#define    DATA1     8」の場合はカッコを付けませんが、
> 「#define    DATA2     DATA1 - 1」の場合はカッコを付けます。
> であれば、問題ないですよね…?

はい、それならば全く問題はありません。

金魚ちゃん 2008/10/24(金) 00:37:50
もう解決しているけど。
僕の意見も。

>でも、ソースコードB、そんなに見ずらいかなぁ…。
これ僕にとってはやり過ぎの部分が多く感じます。(処理a,d,g)
今回の例えではソースコードA(会社の規則スタイル)が見やすいな。

>「縦に長く書くか、横に詰めて書くか」が大きく違うだけで、
>全体的なコード量はほぼ同じなんですけどね…。
上から順に処理を戻らず読めるなら縦長でも良い。
この方が処理を追いやすいから。

ルールについて
>・if文には必ず{}をつけろ
賛成(でも if (条件) break(continue); の場合は付けないね)

>・マルチステートメントにするな
賛成(特に宣言時、一括代入など)

>・goto文、continue文は使うな
反対(goto,continue文を使いこなせない人の考えかもね)

>・比較演算子の「>」は使うな
反対(見やすくなるように使い分けが重要)

>・ソースコードの右側にコメントを記述するな
印刷を考慮するなら賛成(桁数の制限のため)
ソースコードなら反対(上手に使えば良いだけ)

こんな感じです。

rin 2008/10/24(金) 12:38:02
まにさん、金魚さんの書き込みをみて思ったのですが

>という話をよく耳にしますが、それは使い方次第だと思うんですよね。
>反対(goto,continue文を使いこなせない人の考えかもね)
>反対(見やすくなるように使い分けが重要)
>ソースコードなら反対(上手に使えば良いだけ)

「使い方次第」「使いこなす」「使い分ける」「上手に使う」
これが、ルールの理由なんじゃないかな。

「見やすいソースコード」のためのルールの一部として
「プログラマーの個々の能力やセンスに寄らない、
 誰が書いても同じになるように」
ってことが考慮されてるのではないかと

マルチステートメントや、コードの右側コメントなんかも
どのくらいの長さが・・・って
書き手のセンスに頼ってしまう面があると思います

>でも、ソースコードB、そんなに見ずらいかなぁ…。
ソースコードAのほうは、
似たような書き方をネット上やら仕事で見かけるせいもあって
無骨でセンスないけど、見慣れている感があります
ああ、またこの書き方かぁ・・って感じ

PATIO 2008/10/24(金) 14:10:29
goto文に関しては何処にでも飛べるので使いこなすのに
センスとか能力が必要と言う話もわかるのですけれど、
continue文に関しては使いこなせないと駄目なのではと思います。
確かに慣れないと追いにくいと言うのはあるんでしょうけれど、
gotoと違って跳び先が限定されているのでスパゲッティプログラムには
なら無いと思いますし。

私は、皆で共有するソースは、
「単純、素直」が良い
と思っているので、基本的なスタイルはAみたいになるかなと。
今まで比較的よく見るルールに
「3項演算子を使わないと言うのがあります。」
これに関しても代替の解りやすい表現法がありますし、
ソースを読む方のスキル依存を下げる目的なのだと思います。

PATIO 2008/10/24(金) 14:11:45
わはは、括弧の位置を間違えました。
気にしないで下さい。

PSB 2008/10/25(土) 01:42:31
ガイドラインは
・全員のコンセンサスを得る
・逸脱する場合は理由を明記する。
くらいで運用してますな。

MISRA-CとかIPA/SECとかが参考になれば。

まに 2008/10/28(火) 23:13:32
> 「使い方次第」「使いこなす」「使い分ける」「上手に使う」
> これが、ルールの理由なんじゃないかな。

なるほど、そうかもしれませんね。
「分かりやすくなるような使い方をしろ」だと、
結局、人によってその定義が様々だから、
それだったら「ルール化しましょう」ってことなのかも。

自分も、趣味では自分流のルールを定めてはいるのですが、
まだまだ模索中だったりします。
とりあえず、趣味でも「人に見せること」を意識する場合は(滅多にないけど)、
if文のカッコと非マルチステートメント化は、行うようにしようと思います。

でも、マルチステートメントについては、やっぱりどうしても捨てがたいんですよね。
以前、実際に書いたソースですが、

// コマンドによって処理を分岐
if      (strcmp(ComStr, "LIST")  ComList();
else if (strcmp(ComStr, "MAKE")  ComMake();
else if (strcmp(ComStr, "EDIT")  ComEdit();
else if (strcmp(ComStr, "SAVE")  ComSave();
else if (strcmp(ComStr, "OPEN")  ComOpen();
else if (strcmp(ComStr, "SORT")  ComSort();
else if (strcmp(ComStr, "HELP")  ComHelp();

というのが、何十行も続くものを書いたことがあります。
こういう場合だったら、やっぱりマルチステートメントの方が
見やすいと思いませんか………?

> MISRA-CとかIPA/SECとかが参考になれば。
ありがとうございます。じっくり読んでみます。

まに 2008/10/28(火) 23:15:00
if文の閉じるカッコを忘れました…
気にしないでください。

金魚ちゃん 2008/10/29(水) 00:28:02
>// コマンドによって処理を分岐
>if      (strcmp(ComStr, "LIST")  ComList();
>else if (strcmp(ComStr, "MAKE")  ComMake();
>else if (strcmp(ComStr, "EDIT")  ComEdit();
>else if (strcmp(ComStr, "SAVE")  ComSave();
>else if (strcmp(ComStr, "OPEN")  ComOpen();
>else if (strcmp(ComStr, "SORT")  ComSort();
>else if (strcmp(ComStr, "HELP")  ComHelp();
>
>というのが、何十行も続くものを書いたことがあります。
>こういう場合だったら、やっぱりマルチステートメントの方が
>見やすいと思いませんか………?
僕なら関数ポインタを活用して for 文で処理するけどな。

// 例
static struct table_t {
  const char *str;
  void (*pfunc)(void);
} table[] = {
  "LIST", ComList,
  "MAKE", ComMake,
  "EDIT", ComEdit,
  "SAVE", ComSave,
  "OPEN", ComOpen,
  "SORT", ComSort,
  "HELP", ComHelp,
  NULL, NULL,
};

for ( struct table_t *p = table ; p->str != NULL ; p++ ){
  if ( !strcmp(cmdname,p->str) ){
    p->pfunc();
    return;
  }
}
printf( "コマンドエラー\n" );
return;

こんな感じです。

金魚ちゃん 2008/10/29(水) 00:29:31
追記。
コーディング(ルール)も重要ですが
アルゴリズムの追求・研究も重要だと思う。

bun 2008/10/29(水) 08:55:51
>// コマンドによって処理を分岐
>if      (strcmp(ComStr, "LIST")  ComList();
>else if (strcmp(ComStr, "MAKE")  ComMake();
>else if (strcmp(ComStr, "EDIT")  ComEdit();
>else if (strcmp(ComStr, "SAVE")  ComSave();
>else if (strcmp(ComStr, "OPEN")  ComOpen();
>else if (strcmp(ComStr, "SORT")  ComSort();
>else if (strcmp(ComStr, "HELP")  ComHelp();
>
>というのが、何十行も続くものを書いたことがあります。

アルゴリズムの話が出たので一言。
このコード、劇的に遅いです。
CMapを使いましょう。

"LIST","MAKE",...をキーにして、ComList(),ComMake(),...の関数ポインタを
CMap::SetAt()するか、

もう少し分かりやすくするなら、
enum ECmdNum
{
  ECN_List,
  ECN_Make,
    :
};
"LIST","MAKE",...をキーにして、ECN_List,ECN_Make,...をCMap::SetAt()した
上で、
switch()
{
case ECN_List:
  break;
case ECN_Make:
  break;
    :
}

2008/10/29(水) 09:57:21
>CMapを使いましょう。
ん?MFC使用している様には見えないのだが。。

επιστημη [HomePage] 2008/10/29(水) 10:16:17
>>CMapを使いましょう。
>ん?MFC使用している様には見えないのだが。。

「素直に連想配列(辞書)使いなさいよ」の意じゃねぇですかしら。

bun 2008/10/29(水) 10:42:19
そうです、
連想配列(辞書) 要するに ハッシュ を使った方がいいよという意味です。

ただ、連想配列とかハッシュとかそう言う言葉だと知らない人には伝わらないので
あえて、CMapと言ってみました。

かえって分かりづらくなってしまったようで失礼

たいちう 2008/10/29(水) 10:53:21
> というのが、何十行も続くものを書いたことがあります。
> こういう場合だったら、やっぱりマルチステートメントの方が
> 見やすいと思いませんか………?

まにさんが書き直したマルチステートメントのソースコードを貼ったら、
どっちが見やすいかの意見が集まると思いますよ。

επιστημη [HomePage] 2008/10/29(水) 11:02:49
> 連想配列(辞書) 要するに ハッシュ を使った方がいいよという意味です。

ぃゃぃゃ、連想配列(associative-array)とハッシュはまた別物ですぜ。
連想配列の実装のひとつがハッシュであるってだけで。
# std::map だとbinary-tree実装だし

bun 2008/10/29(水) 11:09:16
>ぃゃぃゃ、連想配列(associative-array)とハッシュはまた別物ですぜ。
>連想配列の実装のひとつがハッシュであるってだけで。
># std::map だとbinary-tree実装だし

なるほど、勉強になりました φ(..)メモメモ

2008/10/29(水) 11:22:15
bunさん、イラン突っ込み申し訳ありません。
επιστημηさん、フォローあろがとうございました。
納得です。

まに 2008/10/29(水) 22:45:06
> まにさんが書き直したマルチステートメントのソースコードを貼ったら、
> どっちが見やすいかの意見が集まると思いますよ。

えっとですね、上に貼り付けたソースコードが、自分流スタイルなんですが………
では、比較のために、改めて………


自分流だとこんな感じ。
■ソースコードC
if      (strcmp(ComStr, "LIST"))  ComList();
else if (strcmp(ComStr, "MAKE"))  ComMake();
else if (strcmp(ComStr, "EDIT"))  ComEdit();
else if (strcmp(ComStr, "SAVE"))  ComSave();
else if (strcmp(ComStr, "OPEN"))  ComOpen();
else if (strcmp(ComStr, "SORT"))  ComSort();
else if (strcmp(ComStr, "HELP"))  ComHelp();


これを会社規則に従うとこうなります。
行数が3倍になるし、けっこう見づらいと思うんですが………
■ソースコードD
if (strcmp(ComStr, "LIST")) {
    ComList();
}
else if (strcmp(ComStr, "MAKE")) {
    ComMake();
}
else if (strcmp(ComStr, "EDIT")) {
    ComEdit();
}
else if (strcmp(ComStr, "SAVE")) {
    ComSave();
}
else if (strcmp(ComStr, "OPEN")) {
    ComOpen();
}
else if (strcmp(ComStr, "SORT")) {
    ComSort();
}
else if (strcmp(ComStr, "HELP")) {
    ComHelp();
}


他にも、こんな場合にはマルチステートメントの方が見やすいと思います。
まずは、自分流。
■ソースコードE
str.Format("No:%d",       No1);      StrTextOutput(str);
str.Format("値1:%02d",    Val1);     StrTextOutput(str);
str.Format("値2:%02d",    Val2);     StrTextOutput(str);
str.Format("演算子:%c",   Op);       StrTextOutput(str);
str.Format("答え:%02d",   Ans);      StrTextOutput(str);
str.Format("範囲:%d〜%d", Min,Max);  StrTextOutput(str);


これを会社規則にするとこんな感じ(うぅ…見づらい…)
■ソースコードF
str.Format("No:%02d", No);
StrTextOutput(str);
str.Format("値1:%02d", Val1);
StrTextOutput(str);
str.Format("値2:%02d", Val2);
StrTextOutput(str);
str.Format("演算子:%c", Op);
StrTextOutput(str);
str.Format("答え:%02d", Ans);
StrTextOutput(str);
str.Format("範囲:%d〜%d", Min,Max);
StrTextOutput(str);


ソースコードFに、空行を入れてみます(これならなんとか…)
■ソースコードG
str.Format("No:%02d", No);
StrTextOutput(str);

str.Format("値1:%02d", Val1);
StrTextOutput(str);

str.Format("値2:%02d", Val2);
StrTextOutput(str);

str.Format("演算子:%c", Op);
StrTextOutput(str);

str.Format("答え:%02d", Ans);
StrTextOutput(str);

str.Format("範囲:%d〜%d", Min,Max);
StrTextOutput(str);


文字変数をいくつも定義するのも一つの手ですね。
その場合は、会社規則に従っても見やすくできます。
でも、むやみに変数を定義したくないというのはあります。
■ソースコードH
str1.Format("No:%02d", No);
str2.Format("値1:%02d", Val1);
str3.Format("値2:%02d", Val2);
str4.Format("演算子:%c", Op);
str5.Format("答え:%02d", Ans);
str6.Format("範囲:%d〜%d", Min,Max);

StrTextOutput(str1);
StrTextOutput(str2);
StrTextOutput(str3);
StrTextOutput(str4);
StrTextOutput(str5);
StrTextOutput(str6);


自分の場合、似た処理同士は、上下に並んでいた方が見やすいと思います。
なのでマルチステートメントの方が好きなんですけどね。
皆さんは、CとD、EとFとGでしたら、どちらが見やすいと思いますか?
改めてご意見お聞かせいただければ幸いです。



ソースコードC,Dですが、高速化を求めるなら、
「switch文で先頭の1文字ごとに処理を分け、それからstrcmpで比較する」
という手がありますね。

今さらではありますが、開発環境はVC++2005です。
MFCも一応使ってるのですが、使いこなせてなかったりします。
ヘルプも使いこなせてないですし………

関数ポインタも使ったことありませんし、
連想配列とかハッシュとか言われても、「何ソレ?」って感じで………

知らないことが多すぎますね(^^;)
自分の場合、「知らないと出来ないことがあれば勉強するけど、
そうでなければあえて勉強しない」という、スタンスでいるものでして…
でも、一度みっちり勉強した方がいいかな………という気がしてきました………

maru 2008/10/30(木) 09:06:33
> 自分の場合、似た処理同士は、上下に並んでいた方が見やすいと思います。
> なのでマルチステートメントの方が好きなんですけどね。
似通った処理が続くので、一連の処理を1行で書き、各々の行の違いを際立たせるために
マルチステートメントを多用しているように思われる。

似通った処理が続くのなら、設計を見直すべきで、コーディングスタイル云々で対処すべ
きではないと考えている。
ソースコードC,Dなら金魚ちゃん さんが書いているようにテーブルサーチなり、連想配列
を使用するだろうし、EとFとGなら、StrTextOutput()にフォーマット文字列、引数を渡す
ようにしたりするだろう。

ということで、私の意見は、どちらが見やすいかというより、これらのコードを見た時点
で「なんとかならないの?」って言っちゃいますね。

rin 2008/10/30(木) 12:23:31
ソースコードEは、
一個でも書式指定文字列が長くなったり、変数が増えたりしたものが出た場合
それに合わせて全部の位置が変わるのでしょうか?
ものによってはかなり無駄なスペースができそうな気もしますが・・・

私の場合ですが
・同じような並びが少ないならGタイプにさらにコメントつける
・多いなら、別に専用の関数(変数にいれて出力までのセット)を作り
 それを呼び出す
にします

PATIO 2008/10/30(木) 13:20:06
> ということで、私の意見は、どちらが見やすいかというより、これらのコードを見た時点
> で「なんとかならないの?」って言っちゃいますね。

私も同意見かなぁ。
旨く構造化できるとそれだけで見やすく出来たりしますからね。
あまりにも同じようなコードが続くのであれば、設計その物に
問題はないかと考えた方が良さそうですね。

たいちう 2008/10/30(木) 13:29:06
> えっとですね、上に貼り付けたソースコードが、自分流スタイルなんですが………
> では、比較のために、改めて………

なるほど。
ifの後に続くこともマルチステートメントと書いているのですね。

見易さの点だけ考えるとソースコードCの方が良いと思いますし、
私もそのように書くこともあります。
しかし、コーディングの規則に逆らうほどの利点とは思いません。
if文の{}を強制するルールのメリットの方が大きいと、
会社の人たちは考えているのでしょう。


> ソースコードC,Dですが、高速化を求めるなら、
> 「switch文で先頭の1文字ごとに処理を分け、それからstrcmpで比較する」
> という手がありますね。

これはナンセンス。効率の向上が得られるとしてもわずかですし、
肝心の可読性が大きく落ちます。


> 知らないことが多すぎますね(^^;)
> 自分の場合、「知らないと出来ないことがあれば勉強するけど、
> そうでなければあえて勉強しない」という、スタンスでいるものでして…
> でも、一度みっちり勉強した方がいいかな………という気がしてきました………

コーディングルールにケチを付けるレベルじゃないということでしょう。
会社の他のメンバとまにさんとの技術レベルの差はそれほどないのでしょうが、
会社の人が知らなくても、ルールの元ネタを作った人には何か理由があったのでしょ
う。
switch文の存在も知らない人たちが、ifとelseの書き方でもめるようなことが
起きかねません。この機会に駆け足でおさらいしてはいかがかと。


# 見やすいか見にくいかは慣れの問題が大きいので、
# 会社のルールを使い慣れた人に、自分流のほうが見やすいと
# 論破することは不可能に近いのではないでしょうか。

金魚ちゃん 2008/10/30(木) 22:15:20
この本はどうかな。
http://www.amazon.co.jp/dp/4756136494/
http://www.amazon.co.jp/dp/4894716860/

あと次のサイトも。
http://ameblo.jp/argv/theme-10000021088.html

金魚ちゃん 2008/10/30(木) 22:23:59
追記。
http://sourceforge.jp/projects/libstdc99/document/coding-rule/ja/2/coding-
rule.html
これも。

あー 2008/10/31(金) 13:26:20
http://sourceforge.jp/projects/libstdc99/document/coding-rule/ja/2/coding-
rule.html
はC99の標準ライブラリそのものを開発するときにしか役にたたんだろう

まに 2008/11/03(月) 23:26:01
みなさん、いろいろとご意見ありがとうございました。

「設計を見直せ」というご意見、ごもっともだと思います。
自分も、「もしかしたらツッこまれるかな…」と、覚悟はしてました。

ですが、設計とプログラミングスタイルは、別の問題では…?
「設計がきちんとしてればプログラムもスッキリするはず」というのは
一理ありますが、ここではプログラミングスタイルについての
ご意見をお聞きしたかったのです………
それとも、「設計も含めてプログラミングスタイル」なのでしょうか…?

プログラミングスタイルについては、上述しましたように、
「会社では会社の規則、趣味では自分流」で行こうと思います。
今回の件で、自分流スタイルに「クセ」があることが分かりましたが、
自分自身がそのクセに苦しめられるようなことさえなければ、
あえて直すこともないかな、と思っています。

私は、会社の規則にケチをつけたくて質問したわけではなく、
「自分自身が、後になって自分のプログラミングスタイルに苦しめられることがない
か?」
を確かめたくて質問させていただきました。
ちなみに、会社の人には、自分流スタイルを、見せてさえ、いないです。
会社でプログラミング始める前に、「これこれこういう規則に従え」と言われたもので。
(最初の書き込み文の「受け入れてもらえず」は、語弊がありましたね…)

ただ、勉強不足はちょっと感じたので、C++の本を購入しました。
C言語については一通り勉強してきたつもりですが、
C++については、きちんと勉強してなかったので………

Ban 2008/11/04(火) 02:36:08
> それとも、「設計も含めてプログラミングスタイル」なのでしょうか…?

個人的な意見ですが、物書きの例でいえば、
あまりにひどいもの(頭悪そうな口語体とか漢文風とか統一感がないとか?)を除けば多分、
文体が多少直るより、文書構成自体が直った方が全体的には可読性に影響大なので、
未校正で推敲されてない文書の文体だけ論じることにあまり意味はないと思います。

オクラホマ 2008/11/05(水) 17:21:57
大変興味深く、拝見させて頂いていました。
質問に、便乗させて申し訳ないのですが
金魚ちゃんの、関数ポインタによる、関数の呼び出しを
真似てみたのですが、下記のコードでは、関数を、呼んでいません
間違っている、部分を指摘して、貰えないでしょうか。

#include <iostream>

using namespace std;

class CFoo
{
public:
    void func();
    void func1();
    void func2();
    void func3();
private:
};

void CFoo::func()
{
    cout << "func()" << endl;
}

void CFoo::func1()
{
    cout << "func1()" << endl;
}

void CFoo::func2()
{
    cout << "func2()" << endl;
}

void CFoo::func3()
{
    cout << "func3()" << endl;
}

int main()
{
    CFoo obj;
    struct table_t {
        const char *str;
        void (CFoo::*pfunc)();
    } table[] = {
        "COMOPEN",    &CFoo::func,
        "MAKE",            &CFoo::func1,
        "EDIT",            &CFoo::func2,
        "SAVE",            &CFoo::func3,
        NULL,            NULL,
    };

    for ( table_t *p = table ; p->str != NULL ; p++ ) {
        cout << p->str << endl;
        p->pfunc;    // ここの部分で、CFoo::func〜CFoo::func3が、呼べません
    }

    return 0;
}

επιστημη [HomePage] 2008/11/05(水) 17:38:01
× p->pfunc;
○ (obj.*p->pfunc)();

浩二 2008/11/06(木) 00:15:07
> 「#define    FileClose(a)    if (a!=NULL) { fclose(a);a=NULL; }」は、
> 「#define    FileClose(a)    do { if (a!=NULL) { fclose(a);a=NULL; } } while
> (0)」と
> 書くべきってことか…。

ん? なんか誰もコメントしないけど、
maruさんの指摘は、a じゃ無くて (a) ってことじゃないの?
do, whileなんか意味ないでしょ。。

επιστημη [HomePage] 2008/11/06(木) 08:29:26
> maruさんの指摘は、a じゃ無くて (a) ってことじゃないの?

a=NULL があるから (a)としなくても大抵"ちゃんとコケ"てくれそうです。

> do, whileなんか意味ないでしょ。。

do { ... } while(0) で囲んでおかないと

FileClose(a); else ... がエラーになってくれないってこっちゃないすか?

浩二 2008/11/06(木) 22:23:32
> do { ... } while(0) で囲んでおかないと
> FileClose(a); else ... がエラーになってくれないってこっちゃないすか?

おお、なるほど。
そんなパターンも考えられますね。

FileClose(a) else ...
ですかね。

ただ、
#define    FileClose(a)  { if((a)!=NULL) { fclose(a);(a)=NULL; } }
と{}で括るだけでよいような気もしますが、何か見落としていますか?

maru 2008/11/06(木) 23:30:25
実際には大きな問題にはならないみたいですね。
ちょっと短絡していました。

ただ個人的には
> FileClose(a); else ... がエラーになってくれないってこっちゃないすか?
や
FileClose(a)
とセミコロンなしでもエラーにならないってのは気持ち悪いです。

通りすがり 2008/11/07(金) 03:33:49
#define FileClose(a) ((void)((a)?(fclose(a),(a)=NULL):0))

if文と組み合わせても大丈夫。

rikizo 2008/11/14(金) 17:39:13
> continue禁止

MISRA-Cで決められてるので困ります…。

古いスレッドには追加発言できません。