问题
I've just read: "C void arguments" about the differences between these function definitions in C:
int f(void)
and
int f()
Understanding that the second form means a function returning integer that takes any number of parameters, I wondered how can we actually access and use these unknown parameters?
I'd love to get sample code and explanation.
Also, I know the mechanism of the Varargs in C (with va_arg
, va_end
, va_start
functions) and would be glad to hear about the differences between this mechanism and the f()
form mentioned above.
Thank you a lot!
回答1:
int f(void)
means a function returning int that takes no parameters.
You can see this example to see the consequence of using 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);
}
And also this:-
#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
回答2:
The second version does NOT accept a variable number of parameters, it accepts a fixed (but unspecified) sequence of parameters. In effect, it declares the function, but does not prototype the function. So calls to the function will not be checked for valid types. It's common for the compiler to look at the first call to the function and check other calls against the types found in the first call.
This is why, if you omit #include <stdio.h>
, the first call to printf
will be acceptable, but any calls to printf
with different types will generate an error. Eg.
int main() {
printf("hello"); //<--- accepted, compiler may assume `int printf(char *);`
printf("%s", "world"); //<--- error, type mismatch
}
To have a function accept a variable number, it must have at least one fixed parameter, and then the token ...
.
int f (int first, ...);
You will need to include the stdarg.h
header file. And the function can access the parameters using macros.
void f (int c,...){
va_list ap;
va_start(ap, c);
for(;c--;)
printf("%d", va_arg(ap,int));
va_end (ap);
}
It's convient to have the fixed argument be a count of the remaining arguments. You'll also need to determine the type of each argument somehow. In this example, they are assumed to all be int
.
回答3:
int f(void);
declares f
as a function taking no arguments and returning an int
result, whereas
int f();
declares f
as a function taking a fixed but unspecified number and type of arguments (and, of course, returning an int
result).
Given such a declaration, there has to be a definition somewhere that actually defines the parameters. If it takes no parameters, it might be defined as:
int f() {
return 42;
};
If it takes 2 int
parameters, it might be defined as:
int f(int x, int y) {
return x + y;
}
Either definition is compatible with int f();
, but only the first is compatible with int f(void)
.
A function declaration that specifies the type(s) of the parameters, or, as a special case, uses the void
keyword to specify that there are no parameters, is a prototype. A function declaration that doesn't do this, such as int f();
is an old-style declaration.
Unless you're stuck using a decades-old pre-ANSI compiler that doesn't support prototypes, or you're maintaining very old code and don't have the time or other resources to update it, there is no reason not to use prototypes. If you call a function with no visible prototype, you still have to pass the correct number and type(s) of arguments; the difference is that the compiler will be unable to tell you if the call is incorrect.
(You can define a function that takes a variable number and type of arguments; printf
is an example of this. This is done using the , ...
notation. The function itself uses features defined in <stdarg.h>
to process the arguments. But that has nothing to do with the declarations shown in your question.)
Here's a small program using obsolescent old-style function declarations and definitions:
#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;
}
Note that if I had written add(1, 2, 3, 4)
or add("foo", "bar")
, the compiler wouldn't have caught the error; the program just would have misbehaved.
Here's an equivalent program using modern function declarations and definitions:
#include <stdio.h>
#include <stdlib.h>
int add(int x, int y);
int main(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(int x, int y) {
return x + y;
}
The visible prototype means that the compiler is able to diagnose incorrect calls.
回答4:
As to the f()
form:
click.
An example, a printf-like function that can print decimal numbers or strings into a file descriptor:
#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;
}
来源:https://stackoverflow.com/questions/18792556/use-the-parameters-of-a-function-that-takes-any-number-of-parameters-in-c