C++规范中是否允许存在完全相同的多个翻译单元?
背景回顾
根据C++20规范:
翻译单元指源文件加上所有通过
#include引入的头文件和源文件,减去条件编译跳过的代码;程序由一个或多个翻译单元链接而成,且需遵循单一定义规则(ODR),即多数实体在程序中只能定义一次。
用户实验发现:将同一library.cpp翻译单元两次传入编译器时,链接器会报do_thing()重复定义错误。针对此场景,用户提出以下疑问:
1. C++规范是否允许存在内容完全相同的多个独立翻译单元?
允许。规范并不禁止程序包含内容完全一致的独立翻译单元,只要这些翻译单元内的实体符合ODR要求即可。比如复制一份library.cpp改名为library_copy.cpp,两者内容完全一致,各自作为独立翻译单元编译——只要里面的非内联函数、全局变量等实体标记为static(限制作用域到当前翻译单元),或者通过内联、命名空间等方式满足ODR的例外规则,就不会触发链接错误。
2. 程序是否可包含同一翻译单元的多个实例?
这会直接违反ODR。当你把同一个library.cpp编译出的.o文件多次加入链接,或重复传入编译器生成多个相同的翻译单元实例时,里面的非ODR例外实体(比如未加static的全局函数、全局变量)会出现多个定义,完全不符合规范要求,链接器报错是合理行为。
额外场景:同一翻译单元的.o同时通过静态库链接和动态库运行时加载
这种情况同样会触发ODR冲突。虽然规范里没有直接禁止这种操作方式,但从ODR的核心要求出发,同一个实体(比如do_thing())在程序的静态链接部分和动态加载部分各有一个定义,本质上是同一程序中存在多个实体定义,违反了ODR。这会导致运行时符号解析混乱(比如静态链接版本和动态加载版本可能被错误调用),或直接触发链接/加载阶段的错误,属于未定义行为,无法正常工作是预期结果。
内容的提问来源于stack exchange,提问作者interfect

