
新しいプロジェクトへ配属される度に新しい規約に頭を抱え、
まわりの空気を読んだコーディングを心がける日々を
過ごしているC/C++プログラマです。
この宗教戦争とまで言われているコーディング規約について
プログラマ皆さんの中で、譲れない部分や理由があってこうしている等
マイルールを持っている等ありましたら教えてください。
ちなみに、私はざっと思いだしたもので以下のとおりです。
①if の条件式で定数は右辺?左辺?
左辺に書く派です。
void* p = malloc(...) if (nullptr == p) { return; } 理由は、 極めて稀なケースでしたが、 if (p == nullptr) が if (p = nullptr) に 変更されるといったヒューマンエラーに遭遇した経験があるからです。 この後、コンパイル時に検出できる構文の方が良いと判断し今の形になりました。 最初は違和感を感じていましたが、今は気になりません。
②if, for, switch, whileの中括弧はifと同じ行?次の行??
次の行に書く派です。
理由は、
・{}はスコープを表すものでif等とは別の理由でそこに書かれているから。
・スコープを表しているので{と}は同じインデントに書かれていた方が対になっていると分かりやすく、
縦スクロールの際に見落とすことが少ないから。
③インデントはタブ派?スペース派?
スペース4文字幅のタブ派です。
理由は、
・初めて使ったVisualC++がタブ設定だったから。
・タブを使い続けて問題になったことが無い。
・スペースのインデントがあわせづらいから。(気づかないうちにスペースが増えたり、減ったりする)
・スペースに比べてファイルサイズが小さくなるから。
こんな感じです。
反論や意見、共感。なんでもいいのであなたのスタイルを教えてください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。


回答13件
0
あまり細かい構文の書き方にこだわってもと、ゆるい縛りにしています。
括弧の位置は1つのソース内で統一が取れてればOK。
ただ、タブの展開は、後々の検索の利便性にかかわってくる可能性があるので、
スペース展開するかタブコードを使うかはプロジェクトで統一しています。
あと、原則コンパイラの警告はすべて消す事とかね。
たとえば、①の、if の条件式で定数は…ですが、いまどきのコンパイラは警告を吐くと思いますので規制していません。
どちらかといえば、コーディングスタイルよりも、シンボルの命名規則や、適切なコメントを書く規則を決めた方が有益だと思っています。
投稿2015/11/06 22:05
総合スコア915
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
今まで一番感銘を覚えたのが、Linux カーネル コーディング規約の「第3章 - 括弧の位置と空白」にある次の一節です。
ただし、関数定義の括弧だけは例外で、開始括弧は次の行の始まりに置きます -
【コード例略】
ところが世界中の異教徒たちは、この一貫性の無さが、...そうですね...一貫
性が無いと文句を言っています。しかし、正しい思想を持った人々は (a)
K&R は正しく、しかも(b) K&R が正しいのだとわかっています。それに、とに
かく関数定義というのは特別なものなのです(C言語の中で関数定義のネスト
はできません)。
最後の()の中の文、「C言語の中で関数定義のネストはできません」という所はとても納得させられる物でした。
投稿2015/11/06 22:26
総合スコア21741
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
①if の条件式で定数は右辺?左辺?
右辺派です。
今時のコンパイラなら警告レベルを適切に設定すれば、if文の条件式が代入文になっていると警告を発してくれます。その他見落としがちなミスを指摘してくれたりするので、プロジェクト開始時には必ずコンパイルオプションを確認しましょう。VC++なら警告レベル4に上げましょう。
また、==ならまだしも、不等号でも定数を左辺にするという記述をたまに見かけますが、非常に読みづらいのでコードレビューなどでそのような記述をしているのを見かけたら、私なら訂正させます。
②if, for, switch, whileの中括弧はifと同じ行?次の行??
自分でコードを書く場合は改行してブロックの開始と終了のインデント位置をそろえますね。左側だけ見ていればプログラムの構造が把握できますから。それと、{を行末にすると、特にfor文でそうなりがちですが、条件式が長くなって改行したときに、条件式なのかブロック内の処理なのか見分けがつきにくくなります。
あとは、行単位にすると編集がしやすいということもありますね。ブロックを丸ごとカット&ペーストするというときなど。
ただし、他人のコードを修正するようなときはそっちに合わせます。
③インデントはタブ派?スペース派?
基本4文字のハードタブです。これは重要なのでプロジェクト開始時には規約に入れてメンバーに周知させ、エディターの設定などを確認します。
コーディング「スタイル」に関しては、あまり細かく規定して「規約」に盛り込むと、それこそ宗教戦争的な流れになってしまうので、そうしなければ困るということ以外は個人の裁量に任せた方がいいような気がします。有名なところが出しているコーディング規約は、参考にすることはありますが従う気にはなれません。
T.Kannoさんのご指摘のように命名規則やコメントの充実などを決めた方が良いでしょう。あるいはエラーの伝達方法とか。
追記です。
以下自分で実践している主な規約(?)です。
- 外部公開のクラス・メソッド等にはDoxygen形式でコメントを書く
- それ以外も処理内容が判るように適度にコメントを書く(数か月後に見直したときに思い出せるように)
- シンボル名をあまり省略しすぎない
- 命名規則でいくつかのプリフィックスを決めている(m:メンバ変数、g:グローバル変数、i:入力引数、o:出力引数、等)
- #defineでなければ実現できない場合を除いて定数定義は列挙子かconst値を使う
- 1行はだいたい130桁程度まで(昔プリンターに出していたときの名残。今ではこれがエディターでもちょうど良い長さ)
- 1行が長すぎて途中で改行する場合は行頭が演算子で始まるようにする(前の行の続きだと即座に判るように)
- 1行に複数の文を記述しない(デバッガーのステップ実行が行単位なので)
- 一項演算子はくっつけて二項演算子は前後に空白を入れる(ただし読みやすさを考えてくっつけることもある)
- 演算子の優先順位が誤解を招きそうな場合は括弧で明確にする(*(p++), x = (a << 1) + 1等)
- ifやforなどと括弧の間に空白は挟まない
- do~whileのwhileはブロック閉じ括弧と同じ行に書く
- switch文のcaseはswitchと同じインデント位置
- ブール値の条件判定では等号・不等号を使わない(if(flag == false)ではなくif(!flag)とする)
- gotoを使う前に本当に必要なのかをよく考える(少なくとも21世紀に入ってから使った記憶はない)
- 同じような記述(関数呼び出しとか変数設定とか)が何行も続くときはなんとなく桁位置をそろえる
- ファイル終端は改行で終わらせる
- フレームワークなどを使わない場合はエラー処理やデバッグの仕組みを先に決める(業務でも重要ですね)
結構ありますね。ガチガチですね。
投稿2015/11/07 01:19
編集2015/11/12 22:49総合スコア5944
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/11/13 01:34

0
規約について不毛な議論に時間を費やすよりは、
- すでにある一般的な規約を流用する。
- 規約に準拠したコード書きやすいようにエディタの設定をする。
- 規約違反をチェックするツールを用意する。
ことが大事とおもいます。
規約の例:
- プログラム言語 C の推奨されるスタイルとコーディング規範 http://www.gfd-dennou.org/arch/comptech/cstyle/cstyle-ja.htm
投稿2015/11/06 21:34
総合スコア22328
0
こんにちは。楽しいテーマをありがとう。
自分自身としては、(発展途上ですが)下記ルールでコーディングしています。(もちろん決められた規約がある時はそれに従ってます。チーム開発時、私が規約を決める時はもう少し異なる視点で緩やかに決めます。)
①if の条件式で定数は右辺?左辺?
私はコンパイラの警告に頼って右辺です。もちろん、コンパイラの警告は全て消す主義です。
②if, for, switch, whileの中括弧はifと同じ行?次の行??
両方やってみたのですが、今は、中括弧の中身が少ない場合は同じ行、多い場合は次の行にすると使い勝手が良いと感じてます。
高々2~3行の時に{で1行消費すると却って見難くなります。数十行ある時に同じ行にしているとブロックの開始位置がパッと見で見つかりにくくなるからです。
③インデントはタブ派?スペース派?
ソースは他の人へ渡す可能性が高いのでエディタの機能でスペースへ変換してます。
秀丸を使っているのですが、保存して再度開いた時に初めてスペースに変わるので、なかなか使い勝手が良いです。
④論理的な区切りをコメントで目立たせてます
大きな区切りほど目立つコメントとしてます。
論理的な構造を強調して視覚化することで、頭に入って来やすいように心がけてます。
⑤識別子の長さ
なるべく単語の一部を略さないようにしています。でも、似たような処理の微妙に異なる変数名は異様に長くなりやすいです。
長過ぎる識別子の目立たない一部が異なると可読性が極端に落ちるし、タイプミスしやすくなるので、そのような時は諦めて省略しています。
識別子の長さが20文字を超えてくるとつらいです。
⑥行の長さ
Google Styleで80文字を推奨しているので、なるべく80文字を超えないようにしてます。
でも、改行せずに並べた方が見やすいケースがあります。(例えば、switch-caseで各case文が1行でほとんど同じことをしているような時等)
そのような時は、A4縦印刷できる上限を限度に1行に入れた方が良いかもと最近感じているところです。
⑦変数の宣言形式
良く言われるのがポインタの*をどちらに付けるかですね。
C++
1char* p; 2char *p;
意味としては前者の方が理解しやすい(char型の変数p)ので、前者としています。
最近は、char p, q;問題ではコンパイラがエラーや警告してくれるので酷いことにはならない筈です。
むしろ、CやC++言語は型の修飾子がどの順序で付くのか非常に分かり難いので、それを少しでも把握しやすいように心がけるよう努力してます。
気にしている人は少ないと思いますが、下記の選択もありますね。
C++
1const char* p; 2char const* p;
今まで前者で書いていたのですが、どうも意味的には後者の方がすっきりすることに最近気が付きました。
const, volatile, *, &, []は型の修飾子であり、[]を除き、修飾子は型の右側から修飾すると考えるのです。
つまり、より左側にある修飾子の方が元の型と密に結びついてます。
「char型←それはconst←そこへのポインタ」って感じです。
日本語的にはconstなchar型へのポインタなのでconst charは妥当なのですが、constな「char型へのポインタ」(char const p;)と混同しやすいです。
「char型←そこへのポインタ←それはconst」の方が分かりやすいように感じてます。
ただ、[]をこのルールに当てはめることができないので残念です。
int[5] data;って書けないし、int data[10][5];は、data[10]が5個あるのではなく、data[5]が10個ですし。
投稿2015/11/07 02:52
編集2015/11/07 02:55総合スコア23274
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
ぶっちゃけた話、「IDEやコンパイラのワーニングの設定を揃えてそのまま」がいちばんいいです。
些末な書式の好き嫌いよりも、自動的に整形してくれたり、
違反を見つけてくれる便利さのほうがはるかに勝ります。
自動整形もバリデーションもできないような規約は
よほど切迫した実際的な問題が無い限りスルーですね。
ゆずれない、といったらそういう部分です。
それでも、自分の好みというのは確かにあります。
①if の条件式で定数は右辺?左辺?
誤記の見つかりやすさの問題もありますが、
私は JUnit 的なニュアンスで、
期待値 == 実際値
のほうがしっくりきますね。
しかし、そのJUnit も大きく変わってきていますし、
英語話者の感覚では、 if ( p == nullptr ) を、
「if p is nullptr」 と読み下せることを優先するような動機もあるみたいですね。
全体の趨勢がそうなってきたらそちらに合わせた良い場合もあるのかな的なことは思っています。
②if, for, switch, whileの中括弧はifと同じ行?次の行??
K&R から入っているので同じ行にあるほうがすわりが良いです。
{} がスコープを示すのは事実ですが、
頭に文が無いと、逆に純粋にスコープのためだけに使う {}との見分け方が紛らわしくなりませんか?
・スコープの記号だから行を変える
・単純スコープとの区別のために同じ行に書く
という二つの理由は私にはどちらも同じ程度納得がいくものですです。
ですから、あるいみ「どちらでもいい」気はします。
慣れの上から、同じ行にあったほうがいいと思うだけです。
ただ、else だけは、
C
1} else {
のような形で一行にしてほしいという気もします。
else if で複数の条件が書かれている場合に、
else の記述が複数行にわたっていると、
条件と分岐の記述と、各条件における処理の記述が一目で見分けにくくなる気がします。
{} に関しては、位置よりも省略の方にこだわりがあります。
自分は {} が省略されているコードを見るとどうもムズムズしてしまいます。
一番の問題は、処理を追加する場合により注意が必要になってしまうということです。
C
1if ( ... ) 2 ... 3else 4 ... 5条件分岐には含まれない処理の記述 6
なんて記述の気色悪さに比べたら、
C
1if ( ... ) 2{ 3 ... 4} 5else 6{ 7 ... 8} 9
と
C
1if ( ... ) { 2 ... 3} else { 4 ... 5} 6
の違いなんて大した問題ではないです。
③インデントはタブ派?スペース派?
派、というか、設定一つで勝手にエディタがやってくれる事柄なので、
他のツールの都合に設定を合わせるだけで、問題が生じない限り普段は意識していません。
経験から、タブはやめた方がいいとは思います。
ソースコードレビューやろうとして、チームリーダが使ったビュワーで自分のソースだけ
インデントが変になるといった問題を回避するために、
プロジェクト参加時にタブを規約で決まっている桁数の空白にするようにエディタに設定しておしまいです。
当然 Makefile だけはタブはタブのままですが。
投稿2016/01/31 05:27
総合スコア1193
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
必須なのはインクルードファイルの構成に関する規約ですね。
放っておくと、すぐにall-in-oneヘッダを作ったり、includeの順序が違うと動かなくなったりするものを平気で作る人たちのお陰で、ソースファイルの依存関係がメチャクチャになりますから。
内容は、大体、GoogleのC++スタイルガイドの<ヘッダファイル>の項目と一緒です。
また、それに関して、C++だとnamespaceに関する規約は必ず入れさせますね。
namespaceの使い方を考えずに作られた規約でそのまま作業している現場がまだ多いですから。
括弧や空白の位置、タブなどは、瑣末な話なのであんまり考えてません。担当者の趣味で決めてもらいます。
投稿2016/01/31 03:39
総合スコア70
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
どれも宗教戦争レベルなので気にするだけ時間の無駄と考えています。
①はWarningが出ていれば直す。出ていなかったら静的解析ツールを使用するべきかと思います。
②、③は本当に議論するだけ無駄だと考えています。
他の方の回答にもありましたが、命名規則・コメント・無駄な空白行を気をつて、
可読性を上げたほうが有意義です。
特に命名規則はコーディングの修正が入ると名と機能が合わなくなることがあるので、
その時点で名もコメントも修正するようにするほうが重要と思います。
投稿2016/01/28 09:55
総合スコア10
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
Doxygen はよく使っていますね。
もちろんDoxygen コメントを入れるのは結構手間です。
そこでエディタのマクロを駆使して関数のヘッダが一撃で自動生成できるものを使っています。
エディタは 秀丸エディタ。これを社内標準にしていてマクロをサーバー上で管理し、こつこつメンテしています。
あまり良いことではありませんが、仕様変更が多く、詳細設計書が書けない事もあり、最終成果物であるソースコードから Doxygen を使って文書を生成しています。
そのためにDoxygen で理解できるようなコメントを大量に入れて構造体の意味等も分かりやすくしています。
私のところでは、賛否両論あることを分かった上で、こんな記述にすることを強く推奨しています。
C
1#define IS_EQUAL_TO == 2#define IS_NOT_EQUAL_TO != 3 if ( bEnableFeature IS_EQUAL_TO TRUE )
これに、さらに秀丸エディタの設定を使って IS_EQUAL_TO は緑に、IS_NOT_EQUAL_TO は赤になるようにしています。
これだと絶対に = 単体にしてしまう間違いはありませんし、色が違うので打ち間違い、勘違いも起こりにくくこの部分でバグったのを見たことがありません。
ご参考まで
投稿2016/01/28 09:25
総合スコア33
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/01/28 09:47
2016/01/28 16:30

0
規約というかコメントの書き方は
doxygenのドキュメントを生成できるようにするのがルールとか。
投稿2016/01/17 03:01

退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
うん、つい最近も大論争したなぁ・・・、ガチガチのC言語使いVSC++使いの大論争。
https://github.com/yumetodo/2015_C_Textbook/issues/59
https://github.com/Nagarei/DxLibEx/wiki/Coding_Style
https://github.com/Nagarei/DxLibEx/issues/9
そもそもCとC++ではコーディング規約は違ってしかるべきなんですよね。たとえば
int f(void)/* C */ { return 0; } int f() //C++ { return 0; }
ちなみにCで前者にするべき理由は、voidと書かないと引数を渡せてしまうからで、C++で後者にするべき理由は短く書けというのと、
C++17のドラフト文章である
P0146R0: Regular Void
では、将来的に廃止することを示唆しているからです。
全般には、
にかなり影響を受けています。ただ最近論争した結果
Linux kernel coding style
にも影響を受けるようになりました。これで思い出したけど、一行あたりの文字数の論争もあったな・・・。私は140文字位だけど。
ではでは本題に。
①if の条件式で定数は右辺?左辺?
もうすこし詳細な場合分けが必要です。
- operator== or operator !=
pvalue、コンパイル時定数、rvalue、実行時定数、const lvalue referenceの順に左側においています
2. operator <
とくにきにしません。というよりoperator=とoperator==が紛らわしいのが問題であって不等号では関係ないと。ちなみに他の不等号演算子ほぼは使いません。理由はSTLのsortで要求するのがoperator<の存在か比較関数の指定なのでこれつかえば間違いないという安心感があります。
3. operator <= or operator > or operator =<
これらはそもそもほとんど使いません
②if, for, switch, whileの中括弧はifと同じ行?次の行??
同じ行です。理由は縦に長くなると、16:9なモニターでは見難くてしかたがないので。
ただし質問にはありませんが関数は次の行にするように最近なりました。理由はSFINAEしたりするとtemplateやら関数の戻り値の後置記法やらnoexceptやらで関数宣言部がながくなり、改行しないと定義部の開始がわかりにくいからです
template<typename T1, typename T2, enable_if_t<std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value, std::nullptr_t> = nullptr> DXLE_CONSTEXPR_CLASS auto dot(const point_c<T1>& p1, const point_c<T2>& p2) DXLE_NOEXCEPT_OR_NOTHROW ->decltype(std::declval<std::remove_cv_t<T1>>() * std::declval<std::remove_cv_t<T2>>()) { return p1.x * p2.x + p1.y * p2.y; }
コンストラクタ書くときも長くなりやすいですしそれとの統一性というのもあります
struct game_c::Impl { Impl(const dxle::pointi& bouninngennA_p, const dxle::pointi& bouninngennB_p) : m_window_s(static_cast<int>(WINDOW_WIDTH), static_cast<int>(WINDOW_HEIGHT)), m_state(), m_back_img(dxle::Graph2D::MakeScreen(m_window_s.x, m_window_s.y)), m_img(make_image_array()), m_sound(make_sound_array()), score(), m_bouninngenn{ { { bouninngennA_p, &m_img["bouninngennA"], &m_img["bouninngennA_fall"]},//棒人形A { bouninngennB_p, &m_img["bouninngennB"], &m_img["bouninngennB_fall"]} //棒人形B } } { this->m_back_img.DrawnOn([this]() {m_img["gake"].DrawExtendGraph({}, m_window_s, false); }); } void state_init() NOEXCEPT; bool normal_con_f() const NOEXCEPT; void move_x(int limit_l_x, int limit_r_x) NOEXCEPT; void fadeout_prelude_masseage(); void fall_bouninngenn(size_t bouninngenn_no, const std::deque<dxle::pointi>& pos_record); const dxle::pointi m_window_s; keystate m_state; dxle::Graph2D::Screen m_back_img; img_arr_t m_img; sound_arr_t m_sound; uint8_t score;//0-100 std::array<obj_info, 2>m_bouninngenn; };
③インデントはタブ派?スペース派?
スペース4文字幅のタブ派です。スペースでもいいんだけど、まともなエディタならタブくらいちゃんと扱えるでしょ(煽り)
投稿2016/01/14 16:06
総合スコア5852
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
この宗教論は昔から白熱しますねw
bool func(
int a, // 改行してここに引数のコメントを書く
double b
)
{
bool hoge = false;
for (int i=0; i<100; i++) {
while ( !hoge ) {
if ( getsome() == 1 ) {
hoge = true;
} else {
hoge = false;
}
// hoge = ( getsome() == 1 ); というツッコミはなしでw
}
}
return hoge;
}
・条件判断式の前後はスペース(日立で覚えた)
・関数最初の{ は改行
・関数内の if () { や while () { と } はそれぞれ1行で対応させる
・} else { もこれで一行
・forの中にスペース入れるかいつも迷うんだけどねー
・return値にはカッコつけない
です。
投稿2016/01/12 18:58
総合スコア118
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。