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
相关产品推荐
相关产品推荐

