使用 g++ 预处理器进行替换会导致链接错误

Substitution using g++ preprocessor makes link error

本文关键字:链接 错误 替换 g++ 预处理 处理器 使用      更新时间:2023-10-16

你们知道为什么下面的代码会让 g++ 出现链接错误吗?(不是编译错误(
我很好奇 g++ 在这里是如何工作的

目的的简要说明

  • 主要用途 AAA类
  • AAA 类使用 BBB 类(BBB 是一个库(
  • 尝试使用预处理器在主函数中将类 BBB 替换为假类

文件结构

project
|-- src
|   |-- main.cpp
|   |-- aaa.h
|   |-- aaa.cpp
|-- lib
|-- bbb.h
|-- bbb.cpp

源文件

  1. 主.cpp
#include <iostream>
#define BBB BBB_substitution
#include "../lib/bbb.h"
#undef BBB
class BBB {
public:
void print() {
std::cout << "Fake: hello world" << std::endl;
}
};
#include "aaa.h"
int main() {
AAA aaa;
aaa.print();
}
  1. aaa.h
#pragma once
#include "../lib/bbb.h"
class AAA {
public:
BBB bbb;
void print();
};
  1. aaa.cpp
#include "aaa.h"
void AAA::print() {
bbb.print();
}
  1. bbb.h
#pragma once
class BBB {
public:
void print();
};
  1. bbb.cpp
#include <iostream>
#include "bbb.h"
void BBB::print() {
std::cout << "Real: hello world" << std::endl;
}

代码中存在 ODR 冲突。该规则规定,类定义在每个翻译单元中需要具有相同的标记序列。即使一个名称不同,ODR 也会中断,并且行为未定义。

翻译单元main.cpp编译如下:

class BBB {
public:
void print() {
std::cout << "Fake: hello world" << std::endl;
}
};

翻译单元bbb.cppaaa.cpp编译为:

class BBB {
public:
void print();
};

print()之后的令牌在main.cpp{,而在bbb.cppaaa.cppprint()之后的下一个令牌是;。只有这样就足以破坏 ODR 并且代码的行为未定义。

若要执行要执行的操作,请将代码不同的BBB::print实现链接:

c++ main.cpp aaa.cpp bbb.cpp       -o normal_executable
c++ main.cpp aaa.cpp bbb_mock.cpp  -o test_code_executable

其中bbb_mock.cpp"模拟"/实现在bbb.h中公开的接口。