marunomaruno-memo

marunomaruno-memo

[C] 可変長引数の関数から可変長引数の関数を呼ぶ

2013年10月27日 | C / C++
                                                                2013-10-27 新規
[C] 可変長引数の関数から可変長引数の関数を呼ぶ
================================================================================

可変長引数の関数から、別の可変長引数の関数を呼び出す。

gcc の拡張機能で、可変長マクロもあるが、あくまでも gcc 拡張なので、可変長引数を
持つ関数を使う。

サンプルとしては、デバッグ用のプリント関数をつくることにする。

デバッグ用なので、マクロ名 NDEBUG が定義されているときは何もしないようにする。そ
して、プリントした後に改行し、flush も行う。

また、プリントする関数なので、標準ライブラリー関数 printf() のように、可変長の引
数を受け取るようにする。

仕様としては、以下のとおり。
    void debugPrint(const char* tag, const char* format, ...);

    引数
        tag     タグ。
        format  プリントする書式
        ...     可変長引数部分。プリントしたい式や値

なお、この関数の中から、可変長リストを引数にとる関数を呼び出すことにする。
仕様としては、以下のとおり。
    void print(const char* tag, const char* format, va_list args);

    引数
        tag     タグ
        format  プリントする書式
        args    可変長リスト


□ vargs_sample.c
---
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> // (1)

void debugPrint(const char* tag, const char* format, ...);  // (2)
void print(const char* tag, const char* format, va_list args);  // (3)

int main(void) {
    printf("Start¥n");

    debugPrint("TEST", "[%d %d]", 123, 456);    // (4)

    printf("End¥n");

    return EXIT_SUCCESS;
}

void debugPrint(const char* tag, const char* format, ...) {
#ifndef NDEBUG      // (5)
    va_list args;   // (6)
    va_start(args, format); // (7)
    print(tag, format, args);   // (8)
    va_end(args);   // (9)
#endif
}

void print(const char* tag, const char* format, va_list args) {
    printf("%s ", tag);
    vprintf(format, args);  // (10)
    putchar('¥n');
    fflush(stdout);
}
---

□ 実行結果
---
Start
TEST [123 456]
End
---


(1) #include <stdarg.h>

可変長引数を持った関数を宣言するために必要なヘッダーファイル。


(2) void debugPrint(const char* tag, const char* format, ...);

可変長引数を持った関数のプロトタイプ宣言。
少なくとも、ひとつは引数が必要になる。
だいたいは、この引数に続く可変長部分の形式や数をあらわすものになる。

この使い方は、標準ライブラリー関数の printf() と同じ。
ただし、デバッグ用として、改行が入り、出力した後に flush する。
また、マクロ名 NDEBUG が定義されているときは何も表示しない。


(3) void print(const char* tag, const char* format, va_list args);

可変長の引数をあらわすリスト va_list 型の引数を受け取る関数のプロトタイプ宣言。
この関数は、可変長引数部分を
    const char* format, ...
としてしまうと、実行結果は正しくなくなるので注意。


(4) debugPrint("TEST", "[%d %d]", 123, 456);

可変長の引数を持った関数の呼び出し。
ここでは、デバッグ用のプリント関数 debugPrint() を使っている。


(5) #ifndef NDEBUG

デバッグ用のプリント関数なので、マクロ名 NDEBUG が定義されているときは何も行わな
いようにする。


(6) va_list args;

可変長引数部分をあらわす (可変長リスト) 型 va_list の変数 args を定義する。


(7) va_start(args, format);

可変長リストを初期化する。
最初の引数は、va_list 型の変数。ここに、可変長リストが入る。
2 番目の引数は、可変長引数の直前の引数名。


(8) print(tag, format, args);

可変長リストを引数としてもつ関数の呼び出し。
普通の関数の呼び出しと一緒。


(9) va_end(args);

可変長リストの処理を終了する。


(10) vprintf(format, args);

可変長リストを持った標準ライブラリー関数 printf 関数の呼び出し。
この部分を、
    printf(format, args);
とすると、実行結果は正しくないので注意が必要。


                                                                            以上



最新の画像もっと見る

コメントを投稿