代码之家  ›  专栏  ›  技术社区  ›  R.. GitHub STOP HELPING ICE

使用非原型函数声明是否有效?

  •  3
  • R.. GitHub STOP HELPING ICE  · 技术社区  · 14 年前

    这是有效的C(C99)代码吗?

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

    显然,如果 g 曾被打电话给一个否定的论据 f 不是只需要一个 int 参数,或者如果 是以非否定的论据和 f型 不是一个需要两个 内景 论据。但不然呢?

    以这个单独的源文件为例 从上面提供 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
    
    5 回复  |  直到 14 年前
        1
  •  4
  •   Johannes Schaub - litb    14 年前

    让我们反过来问: 为什么会 有效吗? . 我真的找不到任何禁止上述代码的参数或规则。在相应的另一个分支中的函数调用永远不会执行(尽管注释中的讨论表明这并不容易!).

        2
  •  3
  •   jilles    14 年前

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

    我见过这个(ab)在野外与函数指针一起使用。一系列 void (*)() 包含两个 void (*)(struct Client *) void (*)(struct Client *, int parc, char *parv[]) 函数指针。根据数组索引,代码是否传递了额外的参数。

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

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

        3
  •  2
  •   caf    14 年前

    我同意,只要不正确的函数调用从未被C抽象机求值,它就有效。

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

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

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

        4
  •  0
  •   Ben Jackson    14 年前

    如果是 f(int x, ...) 它看第一个参数的符号,知道它得到了多少(0或1)个vararg?

        5
  •  0
  •   luiscubal    14 年前

    它是有效的(嗯,这可能取决于您使用的标准)。你应该读点关于 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 . 另外,一些调用约定可能会导致严重的问题。