299 lines
5.9 KiB
Markdown
299 lines
5.9 KiB
Markdown
# 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#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 <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`
|
|
|
|
```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` の例
|
|
|
|
```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
|
|
}
|
|
```
|
|
|