我刚才读到:"C void arguments"关于C中这些函数定义之间的差异:
int f(void)
和
int f()
理解第二种形式是指一个函数返回带有任意数量参数的整数,我想知道我们如何实际访问和使用这些未知参数?
我很想获得示例代码和解释。
另外,我知道C语言中Varargs的机制(va_arg
,va_end
,va_start
函数),并且很高兴听到这种机制之间的差异以及上面提到的f()
表格。
非常感谢你!
答案 0 :(得分:7)
第二个版本 NOT 接受可变数量的参数,它接受固定(但未指定)的参数序列。实际上,它声明了函数,但不是原型函数。因此,不会检查对函数的调用是否为有效类型。编译器通常会查看对函数的第一次调用,并针对第一次调用中找到的类型检查其他调用。
这就是为什么,如果省略#include <stdio.h>
,第一次调用printf
将是可以接受的,但是对printf
的不同类型的任何调用都会产生错误。例如
int main() {
printf("hello"); //<--- accepted, compiler may assume `int printf(char *);`
printf("%s", "world"); //<--- error, type mismatch
}
要让函数接受变量号,它必须至少有一个固定参数,然后是令牌...
。
int f (int first, ...);
您需要包含stdarg.h
标头文件。该函数可以使用宏访问参数。
void f (int c,...){
va_list ap;
va_start(ap, c);
for(;c--;)
printf("%d", va_arg(ap,int));
va_end (ap);
}
将固定参数作为剩余参数的计数是很方便的。你还需要以某种方式确定每个参数的类型。在此示例中,假设它们都是int
。
答案 1 :(得分:4)
int f(void);
将f
声明为不带参数且返回int
结果的函数,而
int f();
将f
声明为一个函数,该函数采用固定但未指定的数字和参数类型(当然,返回int
结果)。
鉴于此类声明,必须在某处实际定义参数的定义。如果它不带参数,则可以定义为:
int f() {
return 42;
};
如果需要2 int
个参数,则可能定义为:
int f(int x, int y) {
return x + y;
}
这两种定义都与int f();
兼容,但只有第一种与int f(void)
兼容。
指定参数类型的函数声明,或者,作为特殊情况,使用void
关键字指定没有参数,是原型 。 不执行此操作的函数声明,例如int f();
是旧式声明。
除非您使用不支持原型的数十年前的ANSI前编译器,或者您维护的代码非常旧,并且没有时间或其他资源来更新它,否则会有没理由不使用原型。如果你调用一个没有可见原型的函数,你仍然需要传递正确的数字和类型的参数;区别在于编译器无法告诉您调用是否不正确。
(您可以定义一个带有变量数量和参数类型的函数; printf
就是一个例子。这是使用, ...
表示法完成的。函数本身使用{中定义的特征{1}}处理参数。但这与你的问题中显示的声明无关。)
这是一个使用过时的旧式函数声明和定义的小程序:
<stdarg.h>
请注意,如果我写了#include <stdio.h>
#include <stdlib.h>
int add();
int main(argc, argv)
int argc;
char **argv;
{
if (argc == 3) {
/* NOTE: atoi() does no error checking */
printf("sum = %d\n", add(atoi(argv[1]), atoi(argv[2])));
}
else {
fprintf(stderr, "Usage: %s x y\n", argv[0]);
exit(EXIT_FAILURE);
}
}
int add(x, y)
int x, y;
{
return x + y;
}
或add(1, 2, 3, 4)
,编译器就不会发现错误;该计划本来就是行为不端。
这是使用现代函数声明和定义的等效程序:
add("foo", "bar")
可见原型意味着编译器能够诊断不正确的调用。
答案 2 :(得分:1)
关于f()
表格:
click
一个例子,类似printf的函数,可以将十进制数字或字符串打印到文件描述符中:
#include <stdarg.h>
/* Formatted printing into a file descriptor */
int printfd(int fd, char *fmt, ...)
{
int bytes = 0;
int i_val = 0;
va_list va;
va_start(va, fmt);
while (*fmt) {
char *perc = strchr(fmt, '%');
int len = perc == NULL ? strlen(fmt) : perc - fmt;
if (len) {
bytes += write(fd, fmt, len);
fmt += len;
} else {
fmt = perc + 1;
if (*fmt == 0)
continue;
else if (*fmt == '%')
bytes += write(fd, fmt, 1);
else if (*fmt == 'd')
bytes += writedec(fd, va_arg(va, int));
else if (*fmt == 's')
bytes += writestr(fd, va_arg(va, char*));
fmt++;
}
}
va_end(va);
return bytes;
}
答案 3 :(得分:1)
int f(void)
表示返回int的函数,不带参数。
您可以看到此示例以查看使用int f()
的结果#include <stdio.h>
void f();
int main() {
f(); /* prints some garbage */
f(16); /* prints 16 */
return 0;
}
void f(a1)
int a1;
{
printf("%d\n", a1);
}
还有: -
#include <stdio.h>
#include <stdlib.h>
int f();
int f(int x) {
return x;
}
int main (int argc, char *argv[]) {
printf ("%d\n", f(atoi(argv[1])));
return 0;
}
pax> gcc -Wall --std=c99 -o qq qq.c
pax> ./qq 42
42