这是有效的C(C99)代码吗?
int f();
int g(int x)
{
if (x<0) return f(x);
else return f(x,x);
}
显然,如果使用否定参数调用g
并且f
不是采用单个int
参数的函数,或者g
,则程序具有未定义的行为用非负参数调用,f
不是一个带有两个int
参数的函数。但除此之外?
请考虑这个单独的源文件作为示例,该文件从上面调用g
并提供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
答案 0 :(得分:4)
让我们反过来问:为什么不有效?。我真的找不到任何禁止上述代码的论点或规则。从不执行相应其他分支中的函数调用(尽管注释中的讨论表明它并不那么容易!)。
答案 1 :(得分:3)
C99(6.5.2.2函数调用,第8项)表示如果函数定义没有原型,则“不比较”参数和参数的数量和类型。
我已经看到这个(ab)在野外使用了函数指针。 void (*)()
数组包含void (*)(struct Client *)
和void (*)(struct Client *, int parc, char *parv[])
函数指针。根据数组索引,代码是否传递了额外的参数。
在这种情况下,编译器没有(合理的)方法提前检查参数的数量,即使它具有所有相关的代码。
我认为这是脏代码,我修复了那个特定的实例。
答案 2 :(得分:2)
我同意它是有效的,只要不正确的函数调用永远不会被C抽象机器评估。
有另一种更简单的方法可以得出关于链接器的结论:因为这是允许的:
int f();
int (*fp)() = f;
链接器必须能够在不知道其实际定义的情况下找到f()
的地址。因此,必须能够在不知道实际定义的情况下确定其符号。
答案 3 :(得分:0)
如果它是f(int x, ...)
并且它看到它的第一个参数的符号知道它得到了多少(0或1)varargs怎么办?
答案 4 :(得分:0)
它有效(嗯,这可能取决于您使用的是哪种标准)。您应该阅读有关calling conventions的内容。
基本上,如果f
有一个或没有参数,我认为没有问题
如果f
接受两个或多个参数,那么其他参数(除了第一个参数之外)可能会有垃圾(显然是随机的)值。
考虑这段代码:
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);
}
当然,这是一个坏主意。您应该更愿意显式声明所有参数。
您也可以使用int f(void);
明确声明f不带参数。
请注意,C ++的函数重载可能会导致问题,但我认为这不是问题,因为您使用c
标记了问题。
此外,一些调用约定可能会导致严重问题。