> まにさんが書き直したマルチステートメントのソースコードを貼ったら、
> どっちが見やすいかの意見が集まると思いますよ。
えっとですね、上に貼り付けたソースコードが、自分流スタイルなんですが………
では、比較のために、改めて………
自分流だとこんな感じ。
■ソースコード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も一応使ってるのですが、使いこなせてなかったりします。
ヘルプも使いこなせてないですし………
関数ポインタも使ったことありませんし、
連想配列とかハッシュとか言われても、「何ソレ?」って感じで………
知らないことが多すぎますね(^^;)
自分の場合、「知らないと出来ないことがあれば勉強するけど、
そうでなければあえて勉強しない」という、スタンスでいるものでして…
でも、一度みっちり勉強した方がいいかな………という気がしてきました………
> 自分の場合、似た処理同士は、上下に並んでいた方が見やすいと思います。
> なのでマルチステートメントの方が好きなんですけどね。
似通った処理が続くので、一連の処理を1行で書き、各々の行の違いを際立たせるために
マルチステートメントを多用しているように思われる。
似通った処理が続くのなら、設計を見直すべきで、コーディングスタイル云々で対処すべ
きではないと考えている。
ソースコードC,Dなら金魚ちゃん さんが書いているようにテーブルサーチなり、連想配列
を使用するだろうし、EとFとGなら、StrTextOutput()にフォーマット文字列、引数を渡す
ようにしたりするだろう。
ということで、私の意見は、どちらが見やすいかというより、これらのコードを見た時点
で「なんとかならないの?」って言っちゃいますね。
ソースコードEは、
一個でも書式指定文字列が長くなったり、変数が増えたりしたものが出た場合
それに合わせて全部の位置が変わるのでしょうか?
ものによってはかなり無駄なスペースができそうな気もしますが・・・
私の場合ですが
・同じような並びが少ないならGタイプにさらにコメントつける
・多いなら、別に専用の関数(変数にいれて出力までのセット)を作り
それを呼び出す
にします
> ということで、私の意見は、どちらが見やすいかというより、これらのコードを見た時点
> で「なんとかならないの?」って言っちゃいますね。
私も同意見かなぁ。
旨く構造化できるとそれだけで見やすく出来たりしますからね。
あまりにも同じようなコードが続くのであれば、設計その物に
問題はないかと考えた方が良さそうですね。
> えっとですね、上に貼り付けたソースコードが、自分流スタイルなんですが………
> では、比較のために、改めて………
なるほど。
ifの後に続くこともマルチステートメントと書いているのですね。
見易さの点だけ考えるとソースコードCの方が良いと思いますし、
私もそのように書くこともあります。
しかし、コーディングの規則に逆らうほどの利点とは思いません。
if文の{}を強制するルールのメリットの方が大きいと、
会社の人たちは考えているのでしょう。
> ソースコードC,Dですが、高速化を求めるなら、
> 「switch文で先頭の1文字ごとに処理を分け、それからstrcmpで比較する」
> という手がありますね。
これはナンセンス。効率の向上が得られるとしてもわずかですし、
肝心の可読性が大きく落ちます。
> 知らないことが多すぎますね(^^;)
> 自分の場合、「知らないと出来ないことがあれば勉強するけど、
> そうでなければあえて勉強しない」という、スタンスでいるものでして…
> でも、一度みっちり勉強した方がいいかな………という気がしてきました………
コーディングルールにケチを付けるレベルじゃないということでしょう。
会社の他のメンバとまにさんとの技術レベルの差はそれほどないのでしょうが、
会社の人が知らなくても、ルールの元ネタを作った人には何か理由があったのでしょ
う。
switch文の存在も知らない人たちが、ifとelseの書き方でもめるようなことが
起きかねません。この機会に駆け足でおさらいしてはいかがかと。
# 見やすいか見にくいかは慣れの問題が大きいので、
# 会社のルールを使い慣れた人に、自分流のほうが見やすいと
# 論破することは不可能に近いのではないでしょうか。
http://sourceforge.jp/projects/libstdc99/document/coding-rule/ja/2/coding-
rule.html
はC99の標準ライブラリそのものを開発するときにしか役にたたんだろう
みなさん、いろいろとご意見ありがとうございました。
「設計を見直せ」というご意見、ごもっともだと思います。
自分も、「もしかしたらツッこまれるかな…」と、覚悟はしてました。
ですが、設計とプログラミングスタイルは、別の問題では…?
「設計がきちんとしてればプログラムもスッキリするはず」というのは
一理ありますが、ここではプログラミングスタイルについての
ご意見をお聞きしたかったのです………
それとも、「設計も含めてプログラミングスタイル」なのでしょうか…?
プログラミングスタイルについては、上述しましたように、
「会社では会社の規則、趣味では自分流」で行こうと思います。
今回の件で、自分流スタイルに「クセ」があることが分かりましたが、
自分自身がそのクセに苦しめられるようなことさえなければ、
あえて直すこともないかな、と思っています。
私は、会社の規則にケチをつけたくて質問したわけではなく、
「自分自身が、後になって自分のプログラミングスタイルに苦しめられることがない
か?」
を確かめたくて質問させていただきました。
ちなみに、会社の人には、自分流スタイルを、見せてさえ、いないです。
会社でプログラミング始める前に、「これこれこういう規則に従え」と言われたもので。
(最初の書き込み文の「受け入れてもらえず」は、語弊がありましたね…)
ただ、勉強不足はちょっと感じたので、C++の本を購入しました。
C言語については一通り勉強してきたつもりですが、
C++については、きちんと勉強してなかったので………
> それとも、「設計も含めてプログラミングスタイル」なのでしょうか…?
個人的な意見ですが、物書きの例でいえば、
あまりにひどいもの(頭悪そうな口語体とか漢文風とか統一感がないとか?)を除けば多分、
文体が多少直るより、文書構成自体が直った方が全体的には可読性に影響大なので、
未校正で推敲されてない文書の文体だけ論じることにあまり意味はないと思います。
大変興味深く、拝見させて頂いていました。
質問に、便乗させて申し訳ないのですが
金魚ちゃんの、関数ポインタによる、関数の呼び出しを
真似てみたのですが、下記のコードでは、関数を、呼んでいません
間違っている、部分を指摘して、貰えないでしょうか。
#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;
}
× p->pfunc;
○ (obj.*p->pfunc)();
> 「#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なんか意味ないでしょ。。
> maruさんの指摘は、a じゃ無くて (a) ってことじゃないの?
a=NULL があるから (a)としなくても大抵ちゃんとコケてくれそうです。
> do, whileなんか意味ないでしょ。。
do { ... } while(0) で囲んでおかないと
FileClose(a); else ... がエラーになってくれないってこっちゃないすか?
> do { ... } while(0) で囲んでおかないと
> FileClose(a); else ... がエラーになってくれないってこっちゃないすか?
おお、なるほど。
そんなパターンも考えられますね。
FileClose(a) else ...
ですかね。
ただ、
#define FileClose(a) { if((a)!=NULL) { fclose(a);(a)=NULL; } }
と{}で括るだけでよいような気もしますが、何か見落としていますか?