A.2 使用varargs.h来实现可变参数列表
在编写C程序的过程中,随着程序规模的增大,程序员经常感到有必要进行系统化的错误处理。
error("%d is out of bounds", x);
就与下式等效
fprintf(stderr, "error: %d is out of bounds\n", x);
exit(1);
只有一个小细节“梗”住了我们:error函数的参数数目与类型在不同的调用间并非一成不变,而是像printf函数那样可能随调用的不同而变动。一个典型的解决之道是把error函数写成像下面这样,可惜这种做法并不正确:
void error(a, b, c, d, e, f, g, h, i, j, k);
{
fprintf(stderr, "error:");
fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
fprintf(stderr, "\n");
exit(1);
}
因为函数a到k并没有声明,所以它们默认为int类型。当然,error函数至少包括了一个非int类型的参数(即格式字符串)。因此,这个程序能够正常工作就依赖于是否可以用一组整型参数来复制任意类型的数值。
printf函数的第一个参数必须是一个字符串,我们可以通过检查这个字符串来得到其他参数的数目与类型(当然,假定printf函数的调用是正确的)。
为了便于printf函数的实现,这样一种机制就应该拥有以下特性。
*只需要知道函数的第一个参数的类型,就可以对其进行存取。
*一旦第n个参数被成功地存取,第n+1个参数就可以在仅知道类型的情况下进行存取。
*按这种方式存取一个参数所需的时间不应太多。
需要特别注意的是,逆向存取参数,或者随机存取参数,或者以任何非从头到尾的顺序方式来存取参数,都是不必要的。进一步来说,检测参数列表是否结束通常既不必要,也不可能。
大多数C语言实现都是通过一组总称为varargs的宏定义来达到上述目的。这些宏的确切定义虽然与特定的C语言实现有关,