プログラミング作法2. 自己紹介
• mixC++では2011年冬から活動
• C++/C#が好き
• プログラミング教育の研究
13年3月16日土曜日
3. プログラミング作法
• ブライアン・カーニハン
• 当たり前だが重要なこと
• 可読性・保守性
13年3月16日土曜日
4. メニュー
• 命名
• スタイル
• コメント
• 移植性
13年3月16日土曜日
5. 命名
• 「プログラミングは『名前』が9割。」
あるブログより
• 良い名前 ≒ 良いプログラム
13年3月16日土曜日
6. 命名規則
• 全体で統一する
• ルールの内容自体は重要でない
• PascalCase
camelCase
snake_case
13年3月16日土曜日
7. 変数名
• 長く、説明的な名前 グローバル変数
// 現在の入力キューの長さ
int npending = 0;
• 短く、簡潔な名前 ローカル変数
for (i = 0; i < nelems; i++)
for (theElementIndex = 0;
theElementIndex < numberOfElements;
theElementIndex++)
13年3月16日土曜日
8. 関数名
• 「動詞+名詞」が基本
• putchar
• getTime
• 真偽値を返す関数
if (check_digit(c)) ...
if (is_digit(c)) ...
13年3月16日土曜日
9. スタイル
• 全体で統一する
• ルールの内容自体は重要でない
• K&R
BSD/Allman
GNU
13年3月16日土曜日
10. 自然な形の式
• 音読するつもりで書く
• 否定は分かりにくい
if (!(block_id < actblks) || !(block_id >= unblocks))
...
if ((block_id >= actblks) || (block_id < unblocks))
...
13年3月16日土曜日
11. かっこを使おう
• 演算子の優先順位は分かりにくい
• 本来不要な場所にも付ける
leap_year = y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
leap_year = ((y%4 == 0) && (y%100 != 0)) || (y%400 == 0);
13年3月16日土曜日
12. 慣用句と一貫性
i = 0;
while (i <= n-1)
array[i++] = 1.0;
for (i = n; --i >= 0; )
array[i] = 1.0;
for (i = 0; i < n; i++)
array[i] = 1.0; ループの慣用句!
13年3月16日土曜日
13. 慣用句と一貫性
• 他にも様々な慣用句がある
• リストのトラバース
for (p = list; p != NULL; p = p->next)
• 無限ループ
for (;;)
while (1)
13年3月16日土曜日
14. 悪いコメント1
• 当たり前のことはいちいち書くな
/* SUCCESS を返す */
return SUCCESS;
/* ゼロエントリカウンタをインクリメント */
zerocount++;
13年3月16日土曜日
15. 悪いコメント2
• 悪いコードにコメントをつけるな
/* "result"が0ならマッチするものが見つかったので真を返す
そうでなければ"result"はゼロ以外なので偽を返す */
printf("*** isword returns !result = %dn", !result);
return(!result);
printf("*** isword returns matchfound = %dn", matchfound);
return matchfound;
コメント > コードなら怪しい
13年3月16日土曜日
16. 悪いコメントその他
• コードと矛盾したコメント
• 読者の混乱を増大させるコメント
13年3月16日土曜日
17. 良いコメント1
• グローバルデータにコメント
• 必要に応じて参照されるメモ
struct Status { /* プレフィクス+サフィックスリスト */
char *pref[NPREF]; /* プレフィクス用の単語 */
Suffix *suf; /* サフィックスのリスト */
State *next; /* ハッシュテーブル中の次の項目 */
};
13年3月16日土曜日
18. 良いコメント2
• 関数にコメント
• 関数が全体として何をするか
// random: [0..r-1]の範囲の整数を返す
int random(int r)
{
return (int)(Math.floor(Math.random()*r));
}
13年3月16日土曜日
19. 移植性
• 自分の環境だけで動けばいい?
• 自分の環境だって変わる!
• 移植性向上の労力
→優れたプログラミング
13年3月16日土曜日
20. 標準に固執する
• 言語の標準に従う
• ANSI-C, C99, C++11 ...
• 標準ライブラリを使う
• stdio.h, iostream, STL ...
13年3月16日土曜日
21. 条件コンパイル
• 条件コンパイルは避けよう
• 全組合せでテストできますか?
#ifdef _MAC
printf("This is Macintoshr");
#else
ほかのシステムではこの文で構文エラー
#endif
13年3月16日土曜日
22. まとめ
• 命名:説明的な名前 vs 簡単な名前
• スタイル:慣用句で見やすく!
• コメント:整合性を意識
• 移植性:良いプログラムへの道
13年3月16日土曜日
23. 命名するということ
• 名前を付ける
=抽象化
=プログラミング
• 例えば、配列のコピー
13年3月16日土曜日
24. 処理を埋め込む
int main(void)
{
char buf[16], data[N];
int block = 0, i;
...
// 16バイトずつ読み込んで、dataに格納
while (1) {
fread(buf, 1, sizeof(buf), fp);
if (feof(fp)) break;
for (i = 0; i < sizeof(buf); i++)
data[block * sizeof(buf) + i] = buf[i];
block++;
}
}
13年3月16日土曜日
25. 関数に分ける
int main(void)
{
char buf[16], data[N];
int block = 0, i;
...
// 16バイトずつ読み込んで、dataに格納
while (1) {
fread(buf, 1, sizeof(buf), fp);
if (feof(fp)) break;
copy_array(data + block * sizeof(buf),
buf,
sizeof(buf));
block++;
}
}
13年3月16日土曜日
26. // 16バイトずつ読み込んで、dataに格納
while (1) {
fread(buf, 1, sizeof(buf), fp);
if (feof(fp)) break;
for (i = 0; i < sizeof(buf); i++)
data[block * sizeof(buf) + i] = buf[i];
block++;
抽象化
}
// 16バイトずつ読み込んで、dataに格納
while (1) {
fread(buf, 1, sizeof(buf), fp);
if (feof(fp)) break;
copy_array(data + block * sizeof(buf),
buf,
sizeof(buf));
block++;
}
13年3月16日土曜日