3

这是有效的 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
4

5 回答 5

4

让我们反过来问:为什么它无效. 我真的找不到任何禁止上述代码的论点或规则。各个其他分支中的函数调用永远不会执行(尽管评论中的讨论表明这并不容易!)。

于 2010-11-14T20:20:20.297 回答
3

C99(6.5.2.2 函数调用,第 8 项)表示如果函数定义没有原型,则参数和参数的数量和类型“不进行比较”。

我已经看到这个(ab)在函数指针中被广泛使用。void (*)()包含函数指针void (*)(struct Client *)void (*)(struct Client *, int parc, char *parv[])函数指针的数组。根据数组索引,代码是否传递了额外的参数。

在这种情况下,编译器没有(合理的)方法来预先检查参数的数量,即使它有所有相关的代码。

我认为这是脏代码,我修复了那个特定的实例。

于 2010-11-14T20:53:21.730 回答
2

我同意它是有效的,只要 C 抽象机从未评估过不正确的函数调用。

不过,还有另一种更简单的方法可以得出关于链接器的结论:因为这是允许的:

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

链接器必须能够在f()不知道其实际定义的情况下找到 的地址。因此,它的符号必须能够在不知道实际定义的情况下确定。

于 2010-11-14T21:55:58.167 回答
0

如果它是f(int x, ...)并且它查看它的第一个参数的符号以知道它有多少(0 ​​或 1)可变参数怎么办?

于 2010-11-14T20:01:49.640 回答
0

它是有效的(嗯,它可能取决于您使用的标准)。您应该阅读有关调用约定的内容。

基本上,如果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. 此外,一些调用约定可能会导致严重的问题。

于 2010-11-14T20:06:57.653 回答