4

Why does this compile in Visual Studio:

void foo(int a) {}

int main() {
    foo(1,2);
}

There is a warning

source_file.c(4) : warning C4020: 'foo' : too many actual parameters

but why isn't it an error as it is the case with gcc/clang?

I am aware of K&R-style function definitions, but that would only apply for foo() which would take a variable number of arguments.

Citations from the standard allowing this would be greatly appreciated.

mrks
  • 8,033
  • 1
  • 33
  • 62
  • You can treat it as errors if you enable `/WX`, which is preferred. – herohuyongtao Oct 26 '14 at 05:15
  • I'm not actually using VS. I got code from a student who was able to compile it with VS but I got errors from gcc and clang. Throwing an error seems to be the only reasonable thing for me to do, so I'm trying to understand what VS is doing there. Where does the `2` go? – mrks Oct 26 '14 at 05:17
  • 3
    fyi: VS2013 will treat this as compiler errors: `error C2660: 'foo' : function does not take 2 arguments`. – herohuyongtao Oct 26 '14 at 05:19
  • 5
    The standard does not define "compiler error". It merely requires "diagnostics". A diagnostic could be a warning or error; the standard doesn't distinguish between them. The standard also does not require a compiler to reject a program that generates a diagnostic. – Raymond Chen Oct 26 '14 at 05:25
  • @RaymondChen Thank you - I was completely unaware of that. – mrks Oct 26 '14 at 05:28
  • If you post it as an answer, I'll be happy to accept it. Also, it would be interesting to know where the `2` goes. Is it ignored? – mrks Oct 26 '14 at 05:30
  • The second parameter is evaluated (not much evaluation needed with a integer constant literal) and "passed" to `foo()`. `foo()` ignores it. – chux - Reinstate Monica Oct 26 '14 at 05:32
  • @mdsl Which release of VC is this? Can I guess it is 2008? – codenheim Oct 26 '14 at 05:37
  • Not sure - whatever http://rextester.com/runcode is using. – mrks Oct 26 '14 at 06:03

1 Answers1

4

This is not just MSVC.

GCC accepts it, if your function definition is below the call site and there is no prototype. C has always allowed calling an undeclared function. It infers the prototype from the call-site. So I think the behavior is related to that aspect (though when I move the function above the call-site in GCC, it changes to an error, which makes sense for C99). This should be Undefined Behavior, nonetheless (different number of args than parameters).

int main()
{
   foo(1,2,3);
}

void foo(int a, int b)
{
}

f.c:6:6: warning: conflicting types for ‘foo’ [enabled by default]
 void foo(int a, int b)
      ^
f.c:3:4: note: previous implicit declaration of ‘foo’ was here
    foo(1,2,3);

I found this

6.7.5.3p15:

[...] If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list [this is your situation], both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. [...]

.... but this paragraph is not part of a constraint. Violating a "shall" outside a constraint section is undefined behavior, not must-be-diagnosed behavior (4p2).

I quoted this from : http://compgroups.net/comp.lang.c/why-is-this-not-an-error-in-visual-c/732881

Your mileage may vary.

In short, apparently the only requirement is that the compiler barks at you for some definition of bark. In VS 2013 it is treated as an error.

As far as what happens to the argument, for the same reason that variable argument lists work in C, the call site should push the extra argument, yet the callee will not be aware of it (just guessing here). Though it works, it does not mean it is defined behavior.

Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
codenheim
  • 20,467
  • 1
  • 59
  • 80