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