11

For example,

#include <stdio.h>

void foo();

int main(void)
{
        foo();
        foo(42);
        foo("a string", 'C', 1.0);
        return 0;
}

void foo()
{
        puts("foo() is called");
}

Output:

foo() is called
foo() is called
foo() is called

This code compiles well(without warnings using clang) and runs well. But I wonder what happens to the values passed to foo()? Are they pushed in to the stack or just get discarded?

Perhaps this question sounds useless, but it does make sense. For example, when I have int main(), rather than int main(void), and pass some command line arguments to it, will the behavior of main() be affected?

Also, when using <stdarg.h>, at least one named parameter is required before ... by ISO C. Is it possible that we can make use of such declarations as void foo() to pass from zero to infinite arguments to a function?

I noticed that void foo() is a "non-prototype declaration" and that void foo(void) is a "prototype declaration" just now. Is this somewhat relevant?


Clarification

Seems that this question is marked duplicate to What does an empty parameter list mean? [duplicate](Interestingly, that question is also duplicate...). In fact, I don't think my question have anything to do with that one. It focuses on "What void foo() means in C", but I know this means that "I can pass any number of arguments to it", and I also know it's an obsolescent feature.

But this question is quite different. The keyword is "What if". I just want to know if I pass different amount of arguments to void foo(), just like the example code above, can they be used inside foo()? If so, how is this done? If not, does the passed arguments make any difference? That's my question.

Community
  • 1
  • 1
nalzok
  • 14,965
  • 21
  • 72
  • 139
  • Note that you can't use a parameterless function to pass zero or more variable arguments because the `va_start()` macro requires the name of the last named argument — and if there are no named arguments, it can't work. – Jonathan Leffler Feb 16 '16 at 07:38
  • You're right, `` requires at least one arguments. That's why I want to know if it's possible using a `()`. BTW: I've clarified this question, can you take a look at it? – nalzok Feb 16 '16 at 08:25
  • 2
    The values are pushed onto the stack; the stack gets cleared by the calling function when the function returns (that's the C calling convention; other languages use different conventions, because the called function knows how many arguments it was passed, or how much argument space was used to pass its arguments, and can therefore clear the stack). There's no portable way to use the arguments passed to a function such as `foo()`. – Jonathan Leffler Feb 16 '16 at 08:38
  • @JonathanLeffler So passing arguments to `foo()` doesn't make any make sense in practice? – nalzok Feb 16 '16 at 08:50
  • 1
    No; no sense whatsoever. You might even deem it nonsense. – Jonathan Leffler Feb 16 '16 at 08:51
  • 1
    @JonathanLeffler; I don't think it's a dupe. – haccks Feb 16 '16 at 09:10

2 Answers2

3

As Jonathan Leffler said, C's calling convention establishes that the calling function (not the called one) is responsible for popping arguments from the stack, so the program will not crash even if the arguments do not match what the called function expects.

I'll add that C's calling convention also establishes that arguments are pushed onto the stack in reverse order (i.e. the call foo (1, 2) pushes the 2 then the 1). This allows the called function to access the first parameters even if it doesn't know the rest. For example, a function declared int foo (int a, int b, ...) will be able to access a and b even without knowing what other parameters have been passed: a and b are just at the stack top. Accessing other arguments would require stack pointer hacks, which is just what printf does. Of course, one can easily get funny results by using different arguments from what is expected (say, printf ("%d%d", 3.5);).

So, as per the question, yes, int foo () can be called safely with any number/type of arguments, and in the 1980's it would be considered "normal practice" to use pointer hacks on the stack to access unknown parameters. When portability and readability became more and more of a concern, <stdarg.h> appeared as a portable way to implement these pointer hacks (the compiler will generate the correct code for the target platform, so it is no longer a "hack"). However, as it has been said, <stdarg.h> requires at least one parameter, so it can't help with int foo ().

Jojonete
  • 340
  • 1
  • 8
2

In C, void foo() declares a function that takes an unspecified number of parameters. A function is declared in the following manner:

return-type function-name(parameter-list,...) { body... }

parameter-list is the list of parameters that the function takes separated by commas. If no parameters are given, then the function does not take any and should be defined with an empty set of parenthesis or with the keyword void. If no variable type is in front of a variable in the paramater list, then int is assumed.

zangw
  • 43,869
  • 19
  • 177
  • 214