いつも私を困惑させることが 1 つありますva_end()
。これは実際の関数ではなく、プリプロセッサ マクロであるとよく読みます。これは取るに足らない詳細のように聞こえるかもしれませんが、実際には、va_end()
呼び出す必要がある場所に影響を与える可能性があります。
問題は単純です:複数のステートメントを持つ可変引数関数のva_end()
各ステートメントの前に呼び出す必要がありますか?return
return
次の例の可変個引数関数には、その引数の最初の非 を返すという簡単なタスクがありNULL
ます。ご覧のとおりreturn
、関数本体には 3 つのステートメントがあります。そのうちの 1 つva_start()
が の前後に表示されva_end()
ます。
このコードは正しいですか?
#include <stdio.h>
#include <stdarg.h>
static const void * const FIRST_NON_NULL_END = (void *) "";
void * first_non_null (
const void * const ptr1,
...
) {
if (ptr1) {
return ptr1 == FIRST_NON_NULL_END ? NULL : (void *) ptr1;
}
void * retval;
va_list args;
va_start(args, ptr1);
do {
retval = va_arg(args, void *);
if (retval == FIRST_NON_NULL_END) {
/* Is this correct? Here I do not invoke `va_end()`! */
return NULL;
}
} while (!retval);
va_end(args);
return retval;
}
int main () {
const char * const my_string = first_non_null(
NULL,
NULL,
"autumn",
NULL,
"rose",
FIRST_NON_NULL_END
);
printf("The first non-null value is: \"%s\".\n", my_string);
return 0;
}
編集:
明確にするために、上記の例は、教訓的な目的でのみその形式で書かれています。実際には、次のように、より適切で合成的な方法で書き直すことができます。
#include <stdio.h>
#include <stdarg.h>
static const void * const FIRST_NON_NULL_END = (void *) "";
void * first_non_null (
const void * const ptr1,
...
) {
const void * retval;
va_list args;
va_start(args, ptr1);
for (retval = ptr1; !retval; retval = va_arg(args, const void *))
;;
va_end(args);
return retval == FIRST_NON_NULL_END ? NULL : (void *) retval;
}
int main () {
const char * const my_string = first_non_null(
NULL,
NULL,
"autumn",
NULL,
"rose",
FIRST_NON_NULL_END
);
printf("The first non-null value is: \"%s\".\n", my_string);
return 0;
}