You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言函数单定义规则疑问:为何重定义printf无报错?

为什么重定义printf没有触发单定义规则报错?

先贴出你用到的代码:

#include <stdio.h>

extern int printf(const char *__restrict__format, ...) {
    putchar('a');
}

int main() {
    printf("Hello, world!");
    return 0;
}

先理清几个关键概念

1. Linkage(链接属性)

C语言里标识符的链接属性决定了它在不同编译单元(源文件)中的可见性:

  • 外部链接(external linkage):标识符可以在整个程序的所有编译单元中访问,比如标准库的printf、你自己写的全局函数/变量都属于这类。
  • 内部链接(internal linkage):标识符只能在当前编译单元中访问,用static修饰的函数/变量就是这种。
  • 无链接:比如局部变量,只在当前作用域有效。

printf是带有外部链接的函数,标准库对它的声明和定义都是外部链接的。

2. entire program的含义

标准里的"entire program"指的是最终生成的可执行文件包含的所有代码模块:你的源文件编译后的目标文件、标准库的目标文件/共享库、链接时引入的其他依赖模块。简单说,整个程序是所有参与链接的代码的总和,不是单指你的源文件加头文件(头文件只是被包含到源文件里,属于同一个编译单元)。

为什么你的代码没报错?

核心原因有两个:

  • 首先,stdio.h里的printf只是声明,不是定义。头文件里只会写extern int printf(const char *__restrict format, ...);这类声明,真正的定义在标准库的二进制文件(比如libc.so或者libc.a)里。你的代码里写的是一个完整的函数定义,属于外部定义。
  • 其次,单定义规则(ODR)是C标准的强制要求,但很多链接器默认不会严格检查并报错。当链接器遇到多个同名的外部链接符号时,它通常会选择最后处理的那个定义(或者优先使用用户自己定义的),直接覆盖标准库的printf,而不是抛出重定义错误。如果开启链接器的严格检查选项(比如GCC用-Wl,--fatal-warnings,或者加上-Werror=redundant-decls这类编译选项),就会触发重定义的报错。

对标准条款6.9(5)的理解

这条款明确要求:如果带有外部链接的标识符被使用了,整个程序中必须恰好有一个外部定义;如果没被使用,最多只能有一个。你的代码显然违反了这条规则——整个程序里同时存在你写的printf定义和标准库的printf定义,但链接器的默认行为没有强制执行这条规则,所以你没看到报错。

内容的提问来源于stack exchange,提问作者user51462

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 04:45:37