コーディング規約を追加
This commit is contained in:
parent
2865797a32
commit
12d5c43c9e
298
readme/c-coding-conv.md
Normal file
298
readme/c-coding-conv.md
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
# 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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
336
readme/cpp-coding-conv.md
Normal file
336
readme/cpp-coding-conv.md
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
# C++ コーディング規約
|
||||||
|
|
||||||
|
## 1. 一般的なガイドライン
|
||||||
|
|
||||||
|
1. **モダン C++(C++17 以上)** を前提とする。
|
||||||
|
2. 生ポインタより、まず **`std::unique_ptr` / `std::shared_ptr` / `std::vector` など RAII** を優先する。
|
||||||
|
3. 例外を使う場合は、**例外 or エラーコードのどちらかに統一**する。
|
||||||
|
4. `new` / `delete` は基本的に直接使わず、スマートポインタやコンテナを使う。
|
||||||
|
5. ヘッダ/ソース分割は `*.h` / `*.cpp`(または `*.hpp` / `*.cpp`)で行う。
|
||||||
|
6. 自動整形には **`clang-format`** を利用する。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. コメント/ドキュメント
|
||||||
|
|
||||||
|
### 2.1 ファイルコメント
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// user_service.h - ユーザー関連のユースケースを提供するクラス群
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 クラスコメント(Doxygen 推奨)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
/**
|
||||||
|
* @brief ユーザーを管理するサービスクラス。
|
||||||
|
*
|
||||||
|
* ユーザーの作成、取得、削除などの機能を提供する。
|
||||||
|
*/
|
||||||
|
class UserService {
|
||||||
|
public:
|
||||||
|
/// コンストラクタ
|
||||||
|
explicit UserService(UserRepository& repo);
|
||||||
|
|
||||||
|
/// ユーザーを作成する
|
||||||
|
User createUser(const std::string& name, int age);
|
||||||
|
|
||||||
|
private:
|
||||||
|
UserRepository& repo_;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 メソッドコメント
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
/**
|
||||||
|
* @brief ユーザーをIDで取得する。
|
||||||
|
*
|
||||||
|
* @throws std::runtime_error ユーザーが存在しない場合。
|
||||||
|
*/
|
||||||
|
User UserService::getUserById(int id);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 命名規則
|
||||||
|
|
||||||
|
1. **クラス名/構造体名**: `CamelCase`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class UserService;
|
||||||
|
struct HttpRequest;
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **メソッド・関数名**: `camelCase` または `snake_case`(プロジェクト内で統一)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void addUser(const User& user);
|
||||||
|
int find_user(const std::string& name); // プロジェクト方針次第
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **メンバ変数**:
|
||||||
|
|
||||||
|
* プレフィックスやサフィックスを付けるスタイルが多い
|
||||||
|
例: `snake_case_` / `m_name` / `_name` など
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class User {
|
||||||
|
public:
|
||||||
|
explicit User(std::string name, int age)
|
||||||
|
: name_(std::move(name)), age_(age) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name_;
|
||||||
|
int age_;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **定数**:
|
||||||
|
|
||||||
|
* グローバル定数には `k` プレフィックスを使う場合も多い。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr int kMaxUserCount = 1000;
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **名前空間**: すべて小文字でプロジェクト名などを使う。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace myapp::user {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. インクルードガイドライン
|
||||||
|
|
||||||
|
1. ヘッダでのインクルードは **最小限** にする。前方宣言で済むなら前方宣言を使う。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// user_service.h
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace myapp {
|
||||||
|
|
||||||
|
class UserRepository; // 前方宣言
|
||||||
|
|
||||||
|
class UserService {
|
||||||
|
public:
|
||||||
|
explicit UserService(UserRepository& repo);
|
||||||
|
// ...
|
||||||
|
private:
|
||||||
|
UserRepository& repo_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
2. ソースファイルでは対応するヘッダをまずインクルードし、その後に標準/外部ライブラリ。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// user_service.cpp
|
||||||
|
#include "user_service.h"
|
||||||
|
|
||||||
|
#include "user_repository.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. インクルード順は以下を推奨:
|
||||||
|
|
||||||
|
1. 自分のヘッダ
|
||||||
|
2. 同じモジュールのヘッダ
|
||||||
|
3. 標準ライブラリ
|
||||||
|
4. サードパーティヘッダ
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. エラーハンドリング
|
||||||
|
|
||||||
|
### 5.1 例外を使う場合
|
||||||
|
|
||||||
|
1. ロジック上の失敗には `throw` で例外を投げ、呼び出し側で `try`/`catch`。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
User UserService::getUserById(int id)
|
||||||
|
{
|
||||||
|
auto user = repo_.findById(id);
|
||||||
|
if (!user) {
|
||||||
|
throw std::runtime_error("User not found");
|
||||||
|
}
|
||||||
|
return *user;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 例外の種類は、`std::runtime_error` / `std::invalid_argument` などを使い分ける。
|
||||||
|
|
||||||
|
3. ライブラリ側では「例外を投げる API」と「エラーコードを返す API」を明確に分ける。
|
||||||
|
|
||||||
|
### 5.2 例外を使わない場合
|
||||||
|
|
||||||
|
1. 戻り値に `std::optional<T>` や `expected` パターン(独自実装)を使う。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::optional<User> UserService::tryGetUserById(int id)
|
||||||
|
{
|
||||||
|
return repo_.findById(id);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 複数ファイル間の分割(ヘッダ / ソース)
|
||||||
|
|
||||||
|
### 6.1 例: User と UserService
|
||||||
|
|
||||||
|
```text
|
||||||
|
include/
|
||||||
|
user.h
|
||||||
|
user_service.h
|
||||||
|
src/
|
||||||
|
user.cpp
|
||||||
|
user_service.cpp
|
||||||
|
main.cpp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `user.h`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace myapp {
|
||||||
|
|
||||||
|
class User {
|
||||||
|
public:
|
||||||
|
User(int id, std::string name);
|
||||||
|
|
||||||
|
int id() const;
|
||||||
|
const std::string& name() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int id_;
|
||||||
|
std::string name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `user.cpp`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
namespace myapp {
|
||||||
|
|
||||||
|
User::User(int id, std::string name)
|
||||||
|
: id_(id), name_(std::move(name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int User::id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& User::name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `user_service.h`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
namespace myapp {
|
||||||
|
|
||||||
|
class UserRepository;
|
||||||
|
|
||||||
|
class UserService {
|
||||||
|
public:
|
||||||
|
explicit UserService(UserRepository& repo);
|
||||||
|
|
||||||
|
User createUser(const std::string& name, int age);
|
||||||
|
|
||||||
|
private:
|
||||||
|
UserRepository& repo_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `user_service.cpp`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "user_service.h"
|
||||||
|
|
||||||
|
#include "user_repository.h"
|
||||||
|
|
||||||
|
namespace myapp {
|
||||||
|
|
||||||
|
UserService::UserService(UserRepository& repo)
|
||||||
|
: repo_(repo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
User UserService::createUser(const std::string& name, int age)
|
||||||
|
{
|
||||||
|
// 仮実装: ID採番して保存するなど
|
||||||
|
int newId = repo_.nextId();
|
||||||
|
User user(newId, name);
|
||||||
|
repo_.save(user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. clang-format / clang-tidy / VSCode 設定
|
||||||
|
|
||||||
|
### 7.1 `.clang-format`(C と共有してもOK)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
IndentWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
ColumnLimit: 100
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
NamespaceIndentation: All
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 VSCode 設定例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"[cpp]": {
|
||||||
|
"editor.defaultFormatter": "ms-vscode.cpptools",
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"C_Cpp.clang_format_style": "file",
|
||||||
|
|
||||||
|
// clang-tidy を使う場合
|
||||||
|
"C_Cpp.codeAnalysis.clangTidy.enabled": true,
|
||||||
|
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"files.insertFinalNewline": true
|
||||||
|
}
|
||||||
|
```
|
||||||
Loading…
x
Reference in New Issue
Block a user