コーディング規約を追加
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