6

I'm dealing with some pre-ANSI C syntax. See I have the following function call in one conditional

 BPNN *net;
 // Some more code
 double val;
 // Some more code, and then,
 if (evaluate_performance(net, &val, 0)) {

But then the function evaluate_performance was defined as follows (below the function which has the above-mentioned conditional):

evaluate_performance(net, err)
BPNN *net;
double *err;
{

How come evaluate_performance was defined with two parameters but called with three arguments? What does the '0' mean?

And, by the way, I'm pretty sure that it isn't calling some other evaluate_performance defined elsewhere; I've greped through all the files involved and I'm pretty sure the we are supposed to be talking about the same evaluate_performance here.

Thanks!

skytreader
  • 11,467
  • 7
  • 43
  • 61

4 Answers4

8

If you call a function that doesn't have a declared prototype (as is the case here), then the compiler assumes that it takes an arbitrary number and types of arguments and returns an int. Furthermore, char and short arguments are promoted to ints, and floats are promoted to doubles (these are called the default argument promotions).

This is considered bad practice in new C code, for obvious reasons -- if the function doesn't return int, badness could ensure, you prevent the compiler from checking that you're passing the correct number and types of parameters, and arguments might get promoted incorrectly.

C99, the latest edition of the C standard, removes this feature from the language, but in practice many compilers still allow them even when operating in C99 mode, for legacy compatibility.

As for the extra parameters, they are technically undefined behavior according to the C89 standard. But in practice, they will typically just be ignored by the runtime.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • IIRC, the Unix `open()` function takes an optional 3rd parameter (int mode), which is usually not passed to the function. – David R Tribble Sep 29 '11 at 21:22
  • 1
    @Loadmaster: Unix's [`open(3)`](http://linux.die.net/man/3/open) function is declared as `int open(const char*, int, ...)`: as far as the compiler is concerned, it takes *two or more* parameters, so you can safely call it with 2 or 3 parameters without invoking UB, with or without a prototype. In OP's case, `evaluate_performance` does not have an ellipsis in its definition, so it's UB to call it with anything other than 2 arguments, with or without a prototype in scope. – Adam Rosenfield Sep 29 '11 at 21:49
  • 1
    Unexpected additional arguments can actually cause crashes when a "callee-cleans-up" calling convention is in use. – caf Sep 30 '11 at 06:07
  • 2
    Thanks for the info. *sigh* ... legacy code can really be quite a pain in the neck. :| – skytreader Sep 30 '11 at 06:15
3

The code is incorrect, but in a way that a compiler is not required to diagnose. (A C99 compiler would complain about it.)

Old-style function definitions don't specify the number of arguments a function expects. A call to a function without a visible prototype is assumed to return int and to have the number and type(s) of arguments implied by the calls (with narrow integer types being promoted to int or unsigned int, and float being promoted to double). (C99 removed this; your code is invalid under the C99 standard.)

This applies even if the definition precedes the call (an old-style definition doesn't provide a prototype).

If such a function is called incorrectly, the behavior is undefined. In other words, it's entirely the programmer's responsibility to get the arguments right; the compiler won't diagnose errors.

This obviously isn't an ideal situation; it can lead to lots of undetected errors.

Which is exactly why ANSI added prototypes to the language.

Why are you still dealing with old-style function definitions? Can you update the code to use prototypes?

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • *Raises hands* not my fault. I'd personally avoid any C if I had any choice. This was just given to me, for some reports in a short period of time. Would've ported it to ANSI C if only it wasn't such a large code base or if I had time. Thanks for the information anyway. – skytreader Sep 30 '11 at 06:10
2

Even standard C compilers are somewhat permissive when it comes to this. Try running the following:

int foo()
{
   printf("here");
}

int main()
{
   foo(3,4);
   return 0;
}

It will, to some's surprise, output "here". The extra arguments are just ignored. Of course, it depends on the compiler.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 2
    The extra arguments are undefined behavior. [Appearing to succeed is a valid form of undefined behavior, but it's still undefined](http://blogs.msdn.com/b/oldnewthing/archive/2011/09/29/10217910.aspx). – Adam Rosenfield Sep 29 '11 at 19:17
2

Overloading doesn't exist in C so having 2 declarations would not work in the same text.

That must be a quite old compiler to not err on this one or it did not find the declaration of the function yet!

Some compilers would not warn/err when calling an undefined function. That's probably what you're running into. I would suggest you look at the command line flags of the compiler to see whether there is a flag you can use to get these warnings because you may actually find quite a few similar mistakes (too many parameters is likely to work just fine, but too few will make use of "undefined" values...)

Note that it is possible to do such (add extra parameters) when using the ellipsis as in printf():

printf(const char *format, ...);

I would imagine that the function had 3 parameters at some point and the last was removed because it was unused and some parts of the code was not corrected as it ought to be. I would remove that 3rd parameter, just in case the stack goes in the wrong order and thus fails to send the correct parameters to the function.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • The makefile seem to be calling `cc` (I'm in an Ubuntu environment). `cc` (and `gcc`, for that matter) is version 4.4.3 . It's indeed surprising that I've had smooth builds :| – skytreader Sep 30 '11 at 06:11