现代的编译器(例如gcc), 如果打开编译警告参数, 编译器对标准中的可变参数函数(printf, scanf . . 等) 会进行匹配测试。象问题中的源代码, 用“gcc -Wall” 进行编译, 会给出这样的警告: “warning: int format, long int arg (arg 2)” 在C语言中,可变参数列表的函数是一种允许函数接收不同数量或类型的参数的机制。这种功能在处理如`printf`和`scanf`等标准库函数时非常有用。要创建一个有可变参数的函数,我们需要使用C语言的变长参数(Variable Length Argument List,VLAs)特性。在C99标准以后,C语言引入了`stdarg.h`头文件,提供了处理变长参数的工具。 我们来看一个简单的例子,这个例子展示了如何编写一个函数`vstrcat`,它类似于`strcat`,但可以接受任意数量的字符串并将其连接在一起。`vstrcat`函数的定义如下: ```c #include <stdio.h> // 说明malloc, NULL, size_t #include <stdarg.h> // 说明va_ 相关类型和函数 #include <string.h> // 说明strcat 等 char *vstrcat(const char *first, ...) { size_t len; char *retbuf; va_list argp; char *p; if (first == NULL) return NULL; len = strlen(first); va_start(argp, first); // 初始化变长参数列表 while ((p = va_arg(argp, char *)) != NULL) len += strlen(p); va_end(argp); // 清理变长参数列表 retbuf = malloc(len + 1); // +1 包含终止符\0 if (retbuf == NULL) return NULL; // 出错 (void)strcpy(retbuf, first); va_start(argp, first); // 重新开始扫描 while ((p = va_arg(argp, char *)) != NULL) (void)strcat(retbuf, p); va_end(argp); // 再次清理变长参数列表 return retbuf; } ``` 在这个函数中,我们使用了`va_list`、`va_start`、`va_arg`和`va_end`这四个宏来处理变长参数。这些宏的作用如下: 1. `va_list`:这是一个类型定义,用于声明一个变量,用于存储变长参数列表的信息。 2. `va_start`:初始化变长参数列表,通常在函数内部第一次使用变长参数之前调用。`va_start`接收两个参数,一个是`va_list`类型的变量,另一个是函数的最后一个固定参数。 3. `va_arg`:从变长参数列表中获取下一个参数。它需要`va_list`类型的变量和参数类型作为输入,返回值为参数的值。注意,由于C语言的类型推断机制,你需要显式地提供参数类型,以确保正确地解析变长参数。 4. `va_end`:清理变长参数列表,结束对变长参数的访问,一般在函数结束前调用。 在`vstrcat`函数中,我们首先计算所有字符串的总长度,然后分配足够的内存来存储连接后的字符串。接着,我们通过`va_arg`依次取出每个字符串并使用`strcat`将其追加到结果字符串中。 在调用这个函数时,我们使用一个空指针(NULL)来标记参数列表的结束,如下所示: ```c char *str = vstrcat("Hello, ", "world!", (char *)NULL); ``` 关于编译器警告:“warning: int format, long int arg (arg 2)”,这通常是因为在使用`printf`等格式化输出函数时,格式字符串与提供的参数类型不匹配。例如,如果`printf`的格式字符串期望的是`int`,但实际传入的是`long int`,编译器就会发出警告。为了解决这个问题,我们需要确保格式字符串与传递的参数类型一致。对于`printf`家族的函数,可以使用`%ld`来指定`long int`类型的参数。 总结来说,C语言的变长参数功能允许我们创建灵活的函数,但需要注意正确处理参数类型和使用`stdarg.h`头文件中的相关宏。同时,使用编译器的警告提示可以帮助我们检查代码中可能存在的类型匹配问题,以避免潜在的运行时错误。