Is this dubious use of a non-prototype function declaration valid?

爷,独闯天下 提交于 2019-12-12 13:33:37

问题


Is this valid C (C99) code?

int f();
int g(int x)
{
    if (x<0) return f(x);
    else return f(x,x);
}

Obviously the program has undefined behavior if g is ever called with a negative argument and f is not a function that takes a single int argument, or if g is ever called with a non-negative argument and f is not a function that takes two int arguments. But otherwise?

Consider as an example this separate source file which calls g from the above and provides f:

int g();
#ifdef FOO
int f(int a, int b) { return a+b; }
int main() { return g(1); }
#else
int f(int a) { return a; }
int main() { return g(-1); }
#endif

回答1:


Let's ask the other way around: Why would it not be valid?. I really can't find any argument or rule that forbids the above code. The function call in the respective other branch is never executed (although discussion in the comments indicate it's not so easy!).




回答2:


C99 (6.5.2.2 Function calls, item 8) says the number and types of parameters and arguments "are not compared" if the function definition does not have a prototype.

I have seen this (ab)used in the wild with function pointers. An array of void (*)() contained both void (*)(struct Client *) and void (*)(struct Client *, int parc, char *parv[]) function pointers. Based on the array index, the code passed the extra parameters or not.

In this case, the compiler has no (reasonable) way to check the number of parameters in advance, even if it has all relevant code.

I think this is dirty code and I fixed that particular instance.




回答3:


I would agree that it is valid so long as the incorrect function call is never evaluated by the C abstract machine.

There is another, simpler, way to come to your conclusion about the linker, though: Since this is allowed:

int f();
int (*fp)() = f;

The linker must be able to find the address of f() without knowing its actual definition. Its symbol must therefore be able to be determined without knowing the actual definition.




回答4:


What if it's f(int x, ...) and it looks at the sign of its first argument to know how many (0 or 1) varargs it got?




回答5:


It is valid(well, it might depend on which standard you are using). You should read something about calling conventions.

Basically, if f takes one or no arguments, I'd expect no problems.
If f takes two or more arguments, those other arguments(other than the first) can be expected to have junk(apparently random) values.

Consider this piece of code:

int f(int x, int y);
int g(int x)
{
   int k; //No value
   if (x<0) return f(x, k);
   else return f(x, x);
}

Of course, it is a bad idea. You should prefer to explicitly declare all arguments.

You may also use int f(void); to explicitly declare that f takes no arguments.

Be aware that C++'s function overloading might cause problems, but I assume this isn't a concern since you tagged your question with c. Also, some calling conventions might cause significant problems.



来源:https://stackoverflow.com/questions/4179366/is-this-dubious-use-of-a-non-prototype-function-declaration-valid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!