5.9 KiB
5.9 KiB
C コーディング規約
1. 一般的なガイドライン
- コード整形は 必ず
clang-formatなどの自動整形ツールに従う。 - インデントは スペース4つ もしくは スペース2つ とし、プロジェクト内で統一する(
clang-formatで強制)。 - 1行の長さは 80〜100文字程度 を目安にする。
- グローバル変数は最小限にし、関数引数と戻り値でデータをやりとりする。
- ポインタ・メモリ管理は明確にし、
malloc/freeの対応関係を書きやすい構造にする。 - ヘッダファイルとソースファイルを分け、宣言は
.h、実装は.cに置く。
ドキュメント構造
- src/ (ソースファイル)
- 実装(implementation)を置く場所(.cや.cpp が入る)
- include/ (ヘッダファイル)
- .h または .hpp が入る
- ほかのモジュールに公開したいインタフェースを記述する
- CMake、Makefile などで
include/をinclude pathに入れれば、どこからでも#include "user.h"で参照できる。`
2. コメント/ドキュメント
2.1 ファイル先頭コメント
各 .c / .h ファイルの先頭には、簡単な説明を書く。
/* user.h - ユーザー管理に関する宣言を提供するモジュール */
#ifndef USER_H
#define USER_H
/* ... */
#endif /* USER_H */
2.2 関数コメント(Doxygen 形式推奨)
公開 API になる関数には、Doxygen 形式のコメントを付けると便利。
/**
* @brief ユーザーを作成する。
*
* @param name ユーザー名(NULL終端文字列)。
* @param age 年齢。
* @return 成功時は0、失敗時は負のエラーコード。
*/
int user_create(const char *name, int age);
2.3 行コメント
複雑なロジックやトリッキーなコードには、意図をコメントで残す。
/* バッファが足りない場合は拡張する */
if (needed_size > buf->capacity) {
/* ... */
}
3. 命名規則
-
関数名/変数名:
snake_caseを使用する。int max_value = 0; int get_max_value(int a, int b); -
構造体名:
snake_caseまたはCamelCaseだが、プロジェクト内で統一する。- typedef を併用する場合は
typedef struct user user_t;のような接尾辞_tを使うこともある。
typedef struct user { int id; char name[64]; } user_t; -
定数マクロ:
UPPER_CASE_SNAKEを使う。#define MAX_USER_NAME_LEN 64 -
列挙型:
typedef enum { STATUS_OK = 0, STATUS_ERROR = -1 } status_t; -
グローバル変数は
g_プレフィックスを付けるなど、わかりやすくする。static int g_initialized = 0;
4. インクルードガイドライン
-
ヘッダファイルのインクルード順:
- 対応する自ヘッダ(
.cと同名の.h) - 標準ライブラリ
- 他のプロジェクトヘッダ
#include "user.h" #include <stdio.h> #include <stdlib.h> #include "logger.h" - 対応する自ヘッダ(
-
.cファイルで 必要なものだけ#includeする。 -
ヘッダは インクルードガード または
#pragma onceを必ず付ける。#ifndef USER_H #define USER_H /* 宣言 */ #endif /* USER_H */
5. エラーハンドリング
-
C では例外がないため、戻り値によるエラーコードを徹底する。
int rc = do_something(); if (rc != 0) { fprintf(stderr, "do_something failed: %d\n", rc); return rc; } -
0を成功、負の値をエラーコードとする慣習が多い(プロジェクトで統一)。 -
リソース確保後に複数のエラーがあり得る場合は、
goto cleanupパターンを使ってリークを防ぐ。int fn(void) { char *buf = NULL; FILE *fp = NULL; int rc = 0; buf = malloc(1024); if (!buf) { rc = -1; goto cleanup; } fp = fopen("file.txt", "r"); if (!fp) { rc = -2; goto cleanup; } /* 正常処理 */ cleanup: if (fp) { fclose(fp); } if (buf) { free(buf); } return rc; }
6. 複数ファイル間の分割(.h / .c)
6.1 基本構造
src/
user.h
user.c
main.c
user.h(宣言)
#ifndef USER_H
#define USER_H
typedef struct user {
int id;
char name[64];
} user_t;
int user_init(user_t *u, int id, const char *name);
void user_print(const user_t *u);
#endif /* USER_H */
user.c(実装)
#include "user.h"
#include <stdio.h>
#include <string.h>
int user_init(user_t *u, int id, const char *name)
{
if (!u || !name) {
return -1;
}
u->id = id;
strncpy(u->name, name, sizeof(u->name) - 1);
u->name[sizeof(u->name) - 1] = '\0';
return 0;
}
void user_print(const user_t *u)
{
if (!u) {
return;
}
printf("User{id=%d, name=%s}\n", u->id, u->name);
}
main.c
#include <stdio.h>
#include "user.h"
int main(void)
{
user_t u;
if (user_init(&u, 1, "Alice") != 0) {
fprintf(stderr, "failed to init user\n");
return 1;
}
user_print(&u);
return 0;
}
7. clang-format / VSCode の設定
7.1 .clang-format の例
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: Never
ColumnLimit: 100
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Allman
7.2 VSCode 設定例(.vscode/settings.json)
{
"[c]": {
"editor.defaultFormatter": "ms-vscode.cpptools",
"editor.formatOnSave": true
},
"C_Cpp.clang_format_style": "file",
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true
}