コーディング規約を追加

This commit is contained in:
ry.yamafuji 2025-12-11 01:11:17 +09:00
parent 2865797a32
commit 12d5c43c9e
3 changed files with 634 additions and 0 deletions

298
readme/c-coding-conv.md Normal file
View 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
View 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
}
```