0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

四日で覚えるC言語【Day 5:関数の構造・プリプロセッサ命令】

Last updated at Posted at 2025-09-17

はじめに

【C言語】 は、1970年代に開発された汎用プログラミング言語で、現在の多くの言語(C++、Java、C#、Go など)の基礎となっています。

特徴としては、OS、デバイスドライバ、組み込みシステムなど、「ハードウェアに近い低レベルな処理」が可能な点です。

【注意】このメモは、C言語を全くしらない人間が、ChatGPTに聞いて適当に書いている、C言語の基本的な記載方法のまとめです。

(内容は確認しながら書いているつもりですが、間違ってたらごめんなさい)


関数の構造

C言語における関数定義の書式

記憶クラス 型 関数名(型を含めた仮引数の並び) {
    処理内容
    return 値;
}

📌 記憶クラス(storage class specifier)
→ 変数や関数の寿命(どれくらい生きているか) や 可視性(どこから参照できるか) を指定する仕組み
👉 auto
意味: 自動変数(ローカル変数)
寿命: 関数やブロックに入った時に作られ、抜けたら消える
可視性: そのブロック内だけ
特徴: デフォルトなので普段は省略される /

👉 static
意味: 静的記憶域期間を持つ
寿命: プログラムの開始から終了まで有効
可視性: 宣言されたスコープに限定される
特徴: 値が関数を抜けても保持される

👉 extern
意味: 外部変数を参照する
寿命: プログラム全体で有効
可視性: 他ファイルからもアクセスできる
特徴: 変数の実体は別の場所にあり、ここでは「宣言」だけ

📌 型(戻り値の型)
👉 int / double / char など

📌 関数名
→ 開発者がつける名前

📌 仮引数の並び
→ それぞれの引数の型+名前


main 関数について

C言語のエントリーポイント(最初に実行される関数)は必ず main です。

int main(void) {
    // 処理内容
    return 0;
}

📌 int main(void)
→ 引数を取らないことを 明示

📌 int main()
→ 古い書き方。規格上は「引数が不定」と解釈されるため、引数チェックがされず バグの原因 になりやすい。

📌 戻り値の意味(終了ステータス):
0 … 正常終了
0 以外 … 異常終了(OSや呼び出し元にエラーを知らせる)


C言語のソースコードは、コンパイル前にプリプロセッサ(前処理系) による処理を受けます。この段階で行われるのが プリプロセッサ命令 です。

主なプリプロセッサ命令

📌 #include

他のファイルを取り込む命令。
よく使うのは標準ライブラリのヘッダファイル:

/* 標準入出力関数 (printf, scanf など) */
#include <stdio.h>   

/* 数値変換, 動的メモリ管理, 乱数 など */
#include <stdlib.h>  

👉 ソースコードにそのヘッダファイルの中身がコピーされるイメージです。

📌 #define

マクロ定義。置換マクロとも呼ばれ、文字列の置換を行います。

#define TRUE  1
#define FALSE 0


while (TRUE) {
    printf("ずっと繰り返します\n");
    break;  // breakで抜けないと無限ループ
}

TRUE は 1 に置き換わる
FALSE は 0 に置き換わる

実際にコンパイルされるときは

while (1) { ... }
に展開されます。

👉 while(1) とは?

while (1) {
    // この処理が無限に繰り返される
}


・条件が常に「真 (1)」なので 無限ループ
・ただし、break; や return; を入れればループを途中で抜けられる

📌 C言語では「ブーリアン型を使わない」

C言語(C99以前)には 真偽値(bool型)が標準で存在しません。
その代わりに、整数で真偽を表現します。

0 → 偽 (false)

0以外 → 真 (true)

なので、条件式には整数の計算結果をそのまま使います。


if 文での使い方

int x = 5;

if (x) {
    printf("xは0ではありません\n");
}


・if (x) は xが0かどうかを判定している
・x = 5 のとき → 0以外 → 真 → 実行される
・x = 0 のとき → 偽 → 実行されない

if (!0) {
    printf("!0 は真です\n");
}


0 は偽
!0 は「NOT 0」なので真
→ この場合、必ず実行される

比較演算子の評価結果

int a = 3, b = 5;

if (a < b) {
    printf("aはbより小さい\n");
}


a < b の結果は「真 → 1」または「偽 → 0」

その整数値を if が判定に利用する


C99以降

C99 からは をインクルードすることで 真偽値型 bool が使えるようになりました。

#include <stdbool.h>

int main(void) {
    bool flag = true;

    if (flag) {
        printf("flagは真です\n");
    }

    flag = false;
    if (!flag) {
        printf("flagは偽です\n");
    }

    return 0;
}


true → 1
false → 0

実際には #define で定義されている(プリプロセッサで展開される)

📌 引数付き置換マクロ(マクロ関数)

#define は引数をとることで、関数のように振る舞うマクロを定義できます。

#include <stdio.h>

// マクロ全体と引数は () で囲む
#define DOUBLE(x) ((x) * 2)

int main(void) {

    printf("5 の 2倍 = %d\n", DOUBLE(5));       // 10
    printf("(3+4) の 2倍 = %d\n", DOUBLE(3+4)); // 14
    return 0;
}


これで DOUBLE(5) → ((5) * 2) → 10 に展開される

#include <stdio.h>

// 条件演算子を使った例(2つの値の大きい方を返す)
#define MAX(a, b) ((a) > (b) ? (a) : (b))

int main(void) {
    // 条件演算子
    printf("大きい方 = %d\n", MAX(10, 20));     // 20
    printf("大きい方 = %d\n", MAX(5+3, 2*6));   // 12
    return 0;
}


実行結果
大きい方 = 20
大きい方 = 12

カッコを忘れるとどうなるか
#define MAX(a, b) a > b ? a : b

このとき

printf("%d\n", MAX(5+3, 2*6));

はプリプロセッサ展開で
「5+3 と 2*6 の大きい方」を返したいところですが、

5+3 > 2*6 ? 5+3 : 2*6

となり、優先順位の関係で意図しない式評価になります。
結果は

5+3 > 2*6 ? 5+3 : 2*6
→ 8 > 12 ? 8 : 12
→ 12

のように一見正しく見えることもありますが、
複雑な式を渡すと誤動作の原因になります。

📌 C言語の条件付きコンパイル(#if / #else / #elif / #endif、#ifdef / #ifndef)

C言語では「マクロの値」や「マクロが定義されているかどうか」で、コンパイルするコードを切り替えることができます。
これは「条件付きコンパイル」と呼ばれ、デバッグ用コードや環境ごとの処理を分けたいときに便利です。

1. #if / #elif / #else / #endif

マクロの値を条件にして、処理を分けます。

#include <stdio.h>

#define VERSION 2   // マクロ定義

int main(void) {

#if VERSION == 1
    printf("バージョン1用の処理\n");
#elif VERSION == 2
    printf("バージョン2用の処理\n");
#else
    printf("その他のバージョン\n");
#endif

    return 0;
}


📌 実行結果

バージョン2用の処理

👉 #if の後には 定数式 を書きます。
👉 #elif(else if)や #else を使って条件分岐できます。
👉 #endif で条件付きコンパイルを終了します。

2. #ifdef / #ifndef

マクロが 定義されているかどうか で処理を分けます。

#include <stdio.h>

#define DEBUG   // DEBUG というマクロを定義

int main(void) {

#ifdef DEBUG
    printf("デバッグ情報を表示\n");
#endif

#ifndef RELEASE
    printf("リリース版ではない\n");
#endif

    return 0;
}


📌 実行結果

デバッグ情報を表示
リリース版ではない

👉 #ifdef MACRO : マクロが 定義されていれば コンパイルされる
👉 #ifndef MACRO : マクロが 未定義なら コンパイルされる

3. 応用例:デバッグ用とリリース用
#include <stdio.h>

// #define DEBUG  // コメントを外せばデバッグモード

int main(void) {

#ifdef DEBUG
    printf("詳細なデバッグ情報を出力\n");
#else
    printf("通常動作\n");
#endif

    return 0;
}

📌 DEBUG を定義すれば

詳細なデバッグ情報を出力

📌 定義しなければ

通常動作

💡 ポイントまとめ

#if / #elif / #else / #endif → マクロの値で条件分岐

#ifdef / #ifndef → マクロが定義されているかどうかで条件分岐

デバッグ用・OSごと・バージョンごとの処理を切り替えるのに便利


📌 プロトタイプ宣言

C言語では、関数を使う前に「プロトタイプ宣言」を書く必要があります。
これは「この関数が存在する」ということをコンパイラに伝えるための宣言です。

#include <stdio.h>

/* プロトタイプ宣言 */
void hello(void);

int main(void) {
    hello();  // ここで関数を呼び出す
    return 0;
}

/* 関数の定義 */
void hello(void) {
    printf("Hello, World!\n");
}


👉 ポイント

ヘッダファイル(.h) にまとめて書き、#include で読み込むのが一般的

printf など標準関数のプロトタイプも stdio.h に書かれており、#include で利用できる。







0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?