为什么函数的定义和声明可以有不同的签名?

4 c function

考虑以下程序(受此处的 Tcl 源代码启发):

测试.h

void func(char* format, ...);
Run Code Online (Sandbox Code Playgroud)

测试.c

#include <stdio.h>

#define func funcDummy
#include "test.h"
#undef func

void func(char *format, char *arg)
{
    printf(format, arg);
}
Run Code Online (Sandbox Code Playgroud)

主文件

#include "test.h"

int main(int argc, char *argv[])
{
    (void) argc;
    (void) argv;
    func("I'm %s\n", "confused");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译时没有警告使用gcc main.c test.c -Wall -Wextra并输出“我很困惑”。

我希望看到关于存在对函数 func 的未解析引用的错误。这是怎么回事?

rob*_*oke 6

这是有效的,因为 C 没有损坏的名称。在 C 中,符号名称是“func”。在 C++ 中,符号名称类似于“_Zblahblah_func_blahblah_E”。C++ 将参数编码为符号名称(稍后由链接器使用)。C 没有。

test.c 定义了函数 void func(char *format, char *arg)。

编译 main.c 时,编译器看到:'void func(char* format, ...);'

然而,链接器将两者都简称为“func”。当链接器看到 main.c 中的调用时,它会将 func 的定义视为简单的“func”(该死的参数)。

碰巧的是,您在 main.c 中传递给它的 args 恰好与 func.c 中预期的那些兼容,因此它神奇地工作。

如果您将文件更改为“cpp”而不是“c”,则会出现链接器错误(因为两个原型的损坏名称将不匹配,并且会出现链接器错误)

TL;DR:C++ 支持函数重载,C 不支持。

  • 就语言而言,这些论点是不兼容的。`func` 的声明表明它是可变的。定义说不是。可变参数和非可变参数函数可以具有完全不同的调用约定,因此行为是未定义的。(大多数实现都可能使其“起作用”——这始终是未定义行为的可能后果之一。) (7认同)