开发者

Please explain How prog works

开发者 https://www.devze.com 2023-01-06 12:05 出处:网络
#include<stdio.h>开发者_如何学Go int f(); int main() { f(1); f(1,2); f(1,2,3); } f(int i,int j,int k)
#include<stdio.h>开发者_如何学Go
int f();

int main()
{

    f(1);
    f(1,2);
    f(1,2,3);
}

f(int i,int j,int k)
{

    printf("%d %d %d",i,j,k);

}

it is running fine(without any error) ...can u plz explain how it executes ? how f(1) and f(1,2) links to f(int,int,int) ?


You must have a different definition of "error" to me :-) What gets printed the first two times you call your f function? I get

1 -1216175936 134513787
1  2          134513787
1  2          3

for my three function calls.

What you're seeing is a holdover from the very early days of C when people played footloose and fancy-free with their function calls.

All that is happening is that you are calling a function f and it's printing out three values from the stack (yes, even when you only give it one or two). What happens when you don't provide enough is that your program will most likely just use what was there anyway, usually leading to data issues when reading and catastrophic failure when writing.

This is perfectly compilable, though very unwise, C. And I mean that in a very real, "undefined behaviour", sense of the word (referring specifically to C99: "If the expression that denotes the called function has a type that does not include a prototype, ... if the number of arguments does not equal the number of parameters, the behaviour is undefined").

You should really provide fully formed function prototypes such as:

void f(int,int,int);

to ensure your compiler picks up this problem, and use ellipses (...) in variable parameter functions.


As an aside, what usually happens under the covers is that the calling function starts with a stack like:

12345678
11111111

and pushes (for example) two values onto a stack, so that it ends up like:

12345678
11111111
2
1

When the called function uses the first three values on the stack (since that's what it wants), it finds that it has 1, 2 and 11111111.

It does what it has to do then returns and the calling function clears those two values off the stack (this is called a caller-makes-good strategy). Woe betide anyone who tries this with a callee-makes-good strategy :-) although that's pretty unusual in C since it makes variable argument functions like printf a little hard to do.


This declaration:

int f();

...tells the compiler "f is a function that takes some fixed number of arguments, and returns int". You then try to call it with one, two and three arguments - C compilers are conceptually one-pass (after preprocessing), so at this point, the compiler doesn't have the information available to argue with you.

Your actual implementation of f() takes three int arguments, so the calls which only provide one and two arguments invoke undefined behaviour - it's an error which means that the compiler isn't required to give you an error message, and anything could happen when you run the program.


int f();

In C this declares a function which take a variable number of arguments i.e. it's equivalent to the following in C++

int f(...);

To check this use the following instead of int f();

int f(void);

This will cause the compiler to complain.

Please note: A C linker quirk is also involved here...the C linker does not validate the arguments being passed to a function at the point of invocation and simply links to the first public symbol with the same name. Thus the use of f() in main is allowed because of the declaration of int f(). But the linker binds the function f(int, int, int) during link time at the invocation sites. Hope that makes some sense (please let me know if it doesn't)


It runs fine since int f() means what other answer has already said: it means unspecified number of arguments. This mean you can call it with the number of arguments that you want (also more than 3), without the compiler saying anything about it.

The reason why it works "under the cover", is that arguments are pushed on the stack, and then accessed "from" the stack in the f function. If you pass 0 arguments, the i, j, k of the function "corresponds" to values on the stack that, from the function PoV, are garbage. Nonetheless you can access their values. If you pass 1 argument, one of the three i j k accesses the value, the others get garbage. And so on.

Notice that the same reasoning works if the arguments are passed in some other way, but anyway these are the convention in use. Another important aspect of these conventions is that the callee is not responsible for adjusting the stack; it is up to the caller, that knows how many argument are pushed for real. If it would be not so, the definition of f could suggest that it has to "adjust" the stack to "release" three integer, and this would cause a crash of some kind.

What you've written is fine for the current standard (on gcc compiles with no warnings even with -std=c99 -pedantic; there's a warning, but it's about the missing int in front of the f definition), even though many people finds it disgusting and call that an "obsolescent feature". For sure, your usage in the example code does not show any usefulness, and likely it can help busting bugs a more binding usage of prototypes! (But still, I prefer C to Ada)

add

A more "useful" usage of the "feature" that does not trigger the "undefined behaviour" issue, could be

#include<stdio.h>
int f();

int main()
{

    f(1);
    f(2,2);
    f(3,2,3);
}

int f(int i,int j,int k)
{
  if ( i == 1 ) printf("%d\n", i);
  if ( i == 2 ) printf("%d %d\n", i, j);
  if ( i == 3 ) printf("%d %d %d\n", i, j, k);
}


When you compile the same program using g++ compiler you see the following errors -

g++ program.c
program.c: In function `int main()':
program.c:2: error: too many arguments to function `int f()'
program.c:6: error: at this point in file
program.c:2: error: too many arguments to function `int f()'
program.c:7: error: at this point in file
program.c:2: error: too many arguments to function `int f()'
program.c:8: error: at this point in file
program.c: At global scope:
program.c:12: error: ISO C++ forbids declaration of `f' with no type

Using gcc with option -std=c99 just gives a warning

Compile the same program with the same standard which g++ is having by default, gives the following message:

gcc program.c -std=c++98
cc1: warning: command line option "-std=c++98" is valid for C++/ObjC++ but not for C

My answer then would be or c compilers conform to a different standard which is not as restrictive as the one which c++ conforms to.


In C a declaration has to declare at least the return type. So

int f();

declares a function that returns the type int. This declaration doesn't include any information about the parameters the function takes. The definition of the function is

f(int i,int j,int k)
{

    printf("%d %d %d",i,j,k);
}

Now it is known, that the function takes three ints. If you call the function with arguments that are different from the definition you will not get a compile-time error, but a runtime error (or if you don't like the negative connotation of error: "undefined behavior"). A C-compiler is not forced by the standard to catch those inconsistencies.

To prevent those errors, you should use proper function prototypes such as

f(int,int,int);           //in your case
f(void);                  //if you have no parameters
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号