C言語

【C言語】第5章第11回:関数のオーバーロード(C言語での疑似的な実現)

関数のオーバーロードは、異なる引数を持つ複数の関数を同じ名前で定義する手法です。C++ではサポートされていますが、C言語では直接のサポートがありません。この章では、C言語で関数のオーバーロードを疑似的に実現する方法を解説します。

1. 関数のオーバーロードとは?

1.1 オーバーロードの概要

オーバーロードとは、関数名を同じにしながら、異なる引数リストを持つ関数を複数定義する技法です。

1.2 C言語での制約

C言語では関数のシグネチャ(関数名+引数の型)が一致する場合、同名の関数を複数定義することはできません。そのため、疑似的な方法を用いる必要があります。

2. 疑似的なオーバーロードの実現方法

2.1 可変引数を使用する方法

例:整数の加算を行う関数

#include <stdio.h>
#include <stdarg.h>

// 可変引数を使用した関数
int add(int count, ...) {
    va_list args;
    va_start(args, count);

    int sum = 0;
    for (int i = 0; i < count; i++) {
        sum += va_arg(args, int);
    }

    va_end(args);
    return sum;
}

int main() {
    printf("Sum of 2, 3: %d\n", add(2, 2, 3));
    printf("Sum of 1, 4, 5: %d\n", add(3, 1, 4, 5));
    return 0;
}

解説:

  • va_listを使って可変引数を管理します。
  • va_startva_endで引数のリストを初期化・終了します。
  • va_argで引数を順に取得します。

2.2 マクロを使用する方法

例:マクロで異なる関数を呼び出す

#include <stdio.h>

// 関数プロトタイプ
void printInt(int num);
void printDouble(double num);

// マクロで関数を切り替え
#define PRINT(x) _Generic((x), \
    int: printInt, \
    double: printDouble)(x)

// 関数の実装
void printInt(int num) {
    printf("Integer: %d\n", num);
}

void printDouble(double num) {
    printf("Double: %.2f\n", num);
}

int main() {
    PRINT(10);       // 整数
    PRINT(3.14);     // 浮動小数点数
    return 0;
}

解説:

  • _Genericを使って、引数の型に応じた関数を呼び出します。
  • 型に依存した処理を柔軟に実現できます。

3. 応用例:異なる型のデータを出力する関数

3.1 プログラム例

#include <stdio.h>

// 関数プロトタイプ
void printData(int type, void *data);

// 定数でデータ型を指定
#define TYPE_INT 1
#define TYPE_DOUBLE 2

void printData(int type, void *data) {
    switch (type) {
        case TYPE_INT:
            printf("Integer: %d\n", *(int *)data);
            break;
        case TYPE_DOUBLE:
            printf("Double: %.2f\n", *(double *)data);
            break;
        default:
            printf("Unknown type\n");
    }
}

int main() {
    int num = 42;
    double pi = 3.14159;

    printData(TYPE_INT, &num);
    printData(TYPE_DOUBLE, &pi);
    return 0;
}

解説:

  • void *型を使用して汎用的なデータを渡します。
  • switch文でデータ型を判定し、適切な処理を行います。

4. 練習問題

以下の課題に挑戦して、関数の疑似的なオーバーロードを試してみましょう。

  1. 可変引数を使って、複数の浮動小数点数の平均を計算する関数を作成してください。
  2. マクロを使用して、文字列と整数を別々に出力するプログラムを作成してください。
  3. void *型を使用して、異なる型のデータを処理する汎用関数を作成してください。

5. 練習問題の解答と解説

問1の解答

#include <stdio.h>
#include <stdarg.h>

double calculateAverage(int count, ...) {
    va_list args;
    va_start(args, count);

    double sum = 0.0;
    for (int i = 0; i < count; i++) {
        sum += va_arg(args, double);
    }

    va_end(args);
    return sum / count;
}

int main() {
    printf("Average: %.2f\n", calculateAverage(3, 1.5, 2.5, 3.5));
    return 0;
}

6. まとめ

C言語では関数のオーバーロードを直接サポートしていませんが、可変引数やマクロを使って疑似的に実現できます。次回は、関数テンプレートの概念について学びます。