はじめに
MISRA-C関係の話なのですが、可変個引数をどうするか問う言う話をしてみたいと思います。コーディングルール的に使わないとする場合や使うなら動作を文書化する必要があるようです。可変個引数の使い方を調べてみました。それではいってみましょう。
可変個引数関数
可変個引数関数が、使用する処理系でどのような動作をするかを理解した上で使用しないと期待する動作をしない、スタックオーバーフローを発生するなどの可能性がある。 また、引数を可変とした場合、引数の個数と型が明確に定義されないので、可読性が低下する。 MISRA C:2012では、にて定義される関数の使用を禁じている。 可変個引数を持つ関数の定義では、va_list型の変数を引数の参照のために用いる可変個引数関数の定義に際しては、va_list型変数の値が不定とならないように注意する必要がある。CERT CのMSC39-C ではそのような注意が記載されているので、これを参照すると良い。
va_list型変数が出てきたので、追加で調査します。
va_list型は、
C言語で可変個数の引数を扱うための情報を保持するオブジェクト型です.
この型は<stdarg.h>ヘッダファイルで定義されており、可変個引数を処理する各種マクロ(va_start, va_arg, va_end)で使用されます
va_list型の実装は環境によって異なりますが、一般的には以下のような特徴があります
- 32ビットシステムでは、単純なポインタ型として実装されることがあります.
typedef char *va_list;
- 64ビットシステムでは、より複雑な構造を持つ場合があります。これは、レジスタ渡しとスタック渡しの両方に対応するためです.
- 一部の環境では、8バイト(64ビット)のサイズを持つことが報告されています
va_list型の主な用途は以下の通りです:
- va_startマクロで初期化し、可変引数の開始位置を設定します.
- va_argマクロで順次引数を取得します.
- va_endマクロで可変引数の処理を終了します
使用例:
c#include <stdarg.h>
#include <stdio.h>
void func(int num, ...) {
va_list args;
va_start(args, num);
printf("%d\n", va_arg(args, int));
printf("%c\n", va_arg(args, int));
va_end(args);
}
int main(void) {
func(2, 123, 'a');
return 0;
}
この例では、func関数が可変個数の引数を受け取り、va_list型の変数argsを使用して引数にアクセスしています
注意点として、
va_list型のオブジェクトを別の関数に引き渡す場合、その関数内でva_argマクロを使用すると、元の関数でのva_list型オブジェクトの値が不定になる可能性があります. このような場合は、va_endマクロで処理を終了し、必要に応じてva_startマクロを再度呼び出す必要があります.
さいごに
可変個引数を書いてみました。なかなか面白い内容でしたね。是非、参考にしてみてください。
コメント