简体   繁体   中英

Understanding Function Prototypes in C

  1. The code below:

Before

void main()
{
    float x;
    fun(x,x,x);
}
fun(float x,float x){}

doesn't perhaps work because the actual argument is promoted to double, which doesn't match the function definition, Right?

After

void main()
{
    float x;
    fun(x,x,x);
}
fun(double x,double x){}

works. When the compiler can check the data type, why can't it check the number of arguments? which as per the definition must be two only?!!?

  1. Also, what is the Significance of allowing non prototypes like void fun() ; what difference do they make, when they do not help in checking the parameters passed at the function call, why are they supported??

Thanks:)

The prototype must appear before the function call to be useful; either define the function before it is called:

void fun (float x, float y) {} // IMPLICIT TYPING IS BAD JUJU!

int main(void) // Unless the documentation for your compiler *explicitly* says
               // that "void main()" is a legal signature, main should
               // always return int.
{
  float x;
  fun(x,x,x);
  return 0;
}

or declare it separately:

int main(void)
{
  void fun(float x, float y);
  float x;
  fun(x,x,x);
  return 0;
}

void fun(float x, float y) {}

I prefer the first version.

I will answer again (and hope not get get marked down). Since you still seem to be confused.

The C language heritage also confuses this because some things were allowed in early version of C that are now considered bad practice. But for compatibility reasons they are still allowed. C++ does not allow they (hence my comment in my other answer).

The first thing to know is that c and c++ read the source file from top to bottom to work out what you are doing; they dont look forward, not do they go back and adjust their interpretation if they find new information (contrast this with, say, C#).

So in your code when the compiler sees

fun(x,x,x);

It asks itself. 'do I know what 'fun' is. Answer: no. A c++ compiler will give up at that point

x.cpp: In function ‘int main()’:
x.cpp:4: error: ‘fun’ was not declared in this scope

IN order to fix this you have to declare fun before (meaning earlier in the source file) you try to use it. You do this by putting

void fun(float, float);

At the start of the file. THis says to the compiler "somewhere there will be a function called 'fun' that takes 2 floats", the compiler knows that to do what it later sees the call of fun.

Now what about C. C tries to be helpful (or not depending on your viewpoint)

C tries to guess what you mean by (given that you have not told it anything)

fun(x,x,x);

its default is to assume that fun is a function that takes 3 ints and returns an int. Its view is that it might be right and if its wrong then you will fix it Note - it did not look at what parameters you tried to pass to fun. Its just decides that all unknown functions take and return ints.

So now you are down to promotion rules etc. You tried to call a function that takes ints by passing floats or doubles to it. THis will work

In your question you say that float fails but double works. IN my tests both compile but I get a compiler warning. However your definition of fun has no return type (void in this case). If I use your exact syntax then neither compiles

Advice, always declare functions first. Use C++ as a 'better C' compiler. It is much stricter and so more helpful.

This compiles correctly. You are calling an undefined function, which is on a modern compiler a warning.

It will auto-promote float to double, char and short to int and assume an int return.

The second example works even though there are the wrong number of arguments because there are too many, which the normal calling convention silently corrects.

void fun(); is an old-style prototype that only declares the return type but says nothing about arguments.

Other people have explained why it did what it did, but it's worth mentioning that this is why many C programs are read bottom to top. The following will have correct and intended results (well, main's return type is int , but that's just being pedantic):

fun(float x,float x){}

void main()
{
    float x;
    fun(x,x);
}

By defining functions in order like this, you can do away with the need for prototypes for practically all functions (mutual recursion is an exception). Then you can put prototypes for your API functions in the header and keep your local functions static.

When the compiler can check the data type,why cant it check the number of arguments?which as per the definition must be two only?!!?

That's undefined behavior par excellence. The compiler lets you do it because it assumes you know what you are doing. If you put up warning levels and don't get a warning about it, I would switch to another compiler though. It's one thing to assume that you know what you are doing. But it's another thing to assume that you're not making any mistakes, by not warning you about that. Like you already pointed out, it's technically possible to do it, and it's not difficult.

What is the Significance of allowing non prototypes like void fun(); what difference do they make,when they do not help in checking the parameters passed at the function call,why are they supported??

First, they are for backward compatibility. Old pre-standard C didn't have prototypes. Second, having a function pointer that doesn't contain a prototype can be useful:

void f(int i) { /* ... */ }
void g(double d) { /* ... */ }

int main(void) {
  typedef void ftype();
  ftype *ptr[] = { &f, &g };
  ptr[0](42);
  ptr[1](3.1415);
}

That code is valid and its behavior is well defined.

Both should fail to compile; what compiler are you using

Also - you are not using function prototypes; a function prototype is a specification of the called function before the invocation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM