marunomaruno-memo

marunomaruno-memo

[C] 可変長引数

2011年09月03日 | C / C++
                                                                2012-08-25 更新
可変長引数
================================================================================

C 言語での可変長引数を持つ関数の定義は、以下のようにする。

1. 仮引数は、最初の引数に続いて、「...」を続ける

2. 次の    va_list 型の変数を定義して、これを使う。
    va_list list;

3. 可変長引数を使う準備する
    va_start(list, 最初の仮引数);

4. 引数を取得する
    va_arg(list, 仮引数のデータ型)

5. 可変長引数の処理を終了する
    va_end(list);


□ va_func.c
---
/*
 * 可変長引数を確認するサンプル。
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

int va_func(const char* types, ...);    // (1)

int main(void) {
    va_func("idcsxi", 12, 3.14, 'A', "Hello", 56, -78);    // (2)

    return EXIT_SUCCESS;
}

/**
 * 可変長引数を受け取り、フォーマットにしたがって表示する。
 * @param types 引数のデータ型
 *                     i: int 型
 *                     d: double 型
 *                     c: char 型
 *                     s: char* 型
 *     @return 正しく表示できた引数の数
 */
int va_func(const char* types, ...) {
    const char* type;
    int count = 0;

    va_list list;    // (3)
    va_start(list, types);    // (4)

    for (type = types; *type != '
2012-08-25 更新
可変長引数
================================================================================

C 言語での可変長引数を持つ関数の定義は、以下のようにする。

1. 仮引数は、最初の引数に続いて、「...」を続ける

2. 次の va_list 型の変数を定義して、これを使う。
va_list list;

3. 可変長引数を使う準備する
va_start(list, 最初の仮引数);

4. 引数を取得する
va_arg(list, 仮引数のデータ型)

5. 可変長引数の処理を終了する
va_end(list);


□ va_func.c
---
/*
* 可変長引数を確認するサンプル。
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

int va_func(const char* types, ...); // (1)

int main(void) {
va_func("idcsxi", 12, 3.14, 'A', "Hello", 56, -78); // (2)

return EXIT_SUCCESS;
}

/**
* 可変長引数を受け取り、フォーマットにしたがって表示する。
* @param types 引数のデータ型
* i: int 型
* d: double 型
* c: char 型
* s: char* 型
* @return 正しく表示できた引数の数
*/
int va_func(const char* types, ...) {
const char* type;
int count = 0;

va_list list; // (3)
va_start(list, types); // (4)

for (type = types; *type != '\0'; type++) {
switch (*type) {
case 'i':
printf(" int: %d\n", va_arg(list, int)); // (5)
count++;
break;

case 'd':
printf("double: %f\n", va_arg(list, double)); // (5)
count++;
break;

case 'c':
printf(" char: %c\n", (char) va_arg(list, int)); // (5)
count++;
break;

case 's':
printf("string: %s\n", va_arg(list, char*)); // (5)
count++;
break;

default:
printf("(bad type)\n");
va_arg(list, void*); // 空読みする // (5)
break;
}
}

va_end(list); // (6)

return count;
}
---

□ 実行結果
---
int: 12
double: 3.140000
char: A
string: Hello
(bad type)
int: -78
---

(1) 可変長引数の関数のプロトタイプ宣言

int va_func(const char* types, ...); // (1)

仮引数は少なくてもひとつは必ず書く。次のように、仮引数がひとつもないとコンパイル
エラーになる。
int va_func2(...); // コンパイルエラー


(2) 関数の呼び出し

va_func("idcsxi", 12, 3.14, 'A', "Hello", 56, -78); // (2)

最初の引数が文字列であれば、あとは任意の型をいくつでも引数に取れる。
ただし、今回は、この va_func() の仕様として、文字列中で使用できる文字は、i, d, c,
s のいずれかで、これに対応した型として、引数の中で使用できるのは、int, double,
char, char* だけである。


(3) va_list 型の変数を定義

va_list list; // (3)

この変数は、これ以降の処理で使う。


(4) 可変長引数の処理の開始

va_start(list, types); // (4)

2番目の引数は、関数宣言の、可変長引数の直前の引数を使う。


(5) 仮引数の取得

printf(" int: %d\n", va_arg(list, int)); // (5)
printf("double: %f\n", va_arg(list, double)); // (5)
printf(" char: %c\n", (char) va_arg(list, int)); // (5)
printf("string: %s\n", va_arg(list, char*)); // (5)
va_arg(list, void*); // 空読みする // (5)

仮引数は、va_arg() を使う。

va_arg(v,l)
v: va_list 型の変数
l: 取得したい仮引数のデータ型

なお、つぎの型char は指定できず、警告が出る。実行すると、プログラムはアボートす
る。したがって、対応する型を指定して、キャストする。
char -> int
short -> int
float -> double

また、空読みするときは void* とする。void だと、読み捨てたい引数すら読まれない。


(6) 可変長引数の処理の終了

va_end(list); // (6)

'; type++) { switch (*type) { case 'i': printf(" int: %d\n", va_arg(list, int)); // (5) count++; break; case 'd': printf("double: %f\n", va_arg(list, double)); // (5) count++; break; case 'c': printf(" char: %c\n", (char) va_arg(list, int)); // (5) count++; break; case 's': printf("string: %s\n", va_arg(list, char*)); // (5) count++; break; default: printf("(bad type)\n"); va_arg(list, void*); // 空読みする // (5) break; } } va_end(list); // (6) return count; } --- □ 実行結果 --- int: 12 double: 3.140000 char: A string: Hello (bad type) int: -78 --- (1) 可変長引数の関数のプロトタイプ宣言 int va_func(const char* types, ...); // (1) 仮引数は少なくてもひとつは必ず書く。次のように、仮引数がひとつもないとコンパイル エラーになる。 int va_func2(...); // コンパイルエラー (2) 関数の呼び出し va_func("idcsxi", 12, 3.14, 'A', "Hello", 56, -78); // (2) 最初の引数が文字列であれば、あとは任意の型をいくつでも引数に取れる。 ただし、今回は、この va_func() の仕様として、文字列中で使用できる文字は、i, d, c, s のいずれかで、これに対応した型として、引数の中で使用できるのは、int, double, char, char* だけである。 (3) va_list 型の変数を定義 va_list list; // (3) この変数は、これ以降の処理で使う。 (4) 可変長引数の処理の開始 va_start(list, types); // (4) 2番目の引数は、関数宣言の、可変長引数の直前の引数を使う。 (5) 仮引数の取得 printf(" int: %d\n", va_arg(list, int)); // (5) printf("double: %f\n", va_arg(list, double)); // (5) printf(" char: %c\n", (char) va_arg(list, int)); // (5) printf("string: %s\n", va_arg(list, char*)); // (5) va_arg(list, void*); // 空読みする // (5) 仮引数は、va_arg() を使う。 va_arg(v,l) v: va_list 型の変数 l: 取得したい仮引数のデータ型 なお、つぎの型char は指定できず、警告が出る。実行すると、プログラムはアボートす る。したがって、対応する型を指定して、キャストする。 char -> int short -> int float -> double また、空読みするときは void* とする。void だと、読み捨てたい引数すら読まれない。 (6) 可変長引数の処理の終了 va_end(list); // (6)


最新の画像もっと見る

コメントを投稿