这种可疑的使用非专业型函数声明有效吗?
-
10-10-2019 - |
题
此有效的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
解决方案
让我们以另一种方式问: 为什么会 不是 有效吗?. 。我真的找不到任何禁止上述代码的参数或规则。各自其他分支中的函数调用永远不会执行(尽管评论中的讨论表明它并非易事!)。
其他提示
C99(6.5.2.2函数调用,第8项)表示,如果函数定义没有原型,则参数和参数的数量和类型“未比较”。
我已经看到(AB)在野外使用功能指针。一系列 void (*)()
两者都包含 void (*)(struct Client *)
和 void (*)(struct Client *, int parc, char *parv[])
功能指针。基于数组索引,代码是否传递了额外的参数。
在这种情况下,即使具有所有相关代码,编译器也没有(合理的)方法来检查参数的数量。
我认为这是肮脏的代码,我修复了该特定实例。
我同意,只要C Abstract Machine从未评估过不正确的函数调用,它是有效的。
不过,还有另一种简单的方法可以得出有关链接器的结论:因为允许这一点:
int f();
int (*fp)() = f;
链接器必须能够找到 f()
不知道其实际定义。因此,必须在不知道实际定义的情况下确定其符号。
如果是 f(int x, ...)
它查看其第一个论点的迹象是知道它有多少(0或1)varargs?
它是有效的(嗯,这可能取决于您使用的标准)。你应该读一些有关的东西 召集会议.
基本上,如果 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
。另外,一些召集约定可能会引起重大问题。