在不同的编译单元中使用不同的编译标志编译相同的头

Compiling same header with different compilation flag in different compilation units

本文关键字:编译 标志 单元      更新时间:2023-10-16

我遇到了一个奇怪的问题,这个问题打破了我对编译单元封装的理解。

简而言之,我有一个常见的内联函数,它是从一个头中获得的
我将其包含在两个不同的.cpp文件中,并使用不同的#define
但我最终在bot编译单元中得到了相同的实现。

Common.h:

#include <iostream>
inline void printA()
{
#ifdef YES
    std::cout << " yes" << std::endl;
#else
    std::cout << " no" << std::endl;
#endif
}

文件1.h:

void print1();

File1.cpp:

#define YES
#include "Common.h"
#include "File1.h"
void print1()
{
    printA();
}

文件2.h:

void print2();

File2.cpp

#include "Common.h"
#include "File2.h"
void print2()
{
    printA();
}

main.cpp:

#include "File1.h"
#include "File2.h"
int main(int argc, char* argv[])
{
    print1();
    print2();
    return 0;
}

此示例的输出为:

yes
yes

我希望它是:

yes
no

那么,为什么两个编译单元都采用相同的实现方式呢
公共函数甚至是内联的。。。。

我怎样才能得到"预期"的结果?

为什么选择"是"执行?只是汇编顺序的问题?

顺便说一句,我在GCC 4.8和VS2012 上得到了相同的结果

标准(此处为N4527)在3.2中规定了一个定义规则/6

类类型(第9条)、枚举类型(7.2)、内联函数可以有多个定义外部链接(7.1.2)、类模板(第14条)、非静态函数模板(14.5.6)、静态数据成员类模板的成员函数(14.5.1.1),或如果每个定义出现在不同的翻译单元中,前提是定义满足以下要求。鉴于这样一个名为D的实体在多个翻译单元中定义,那么(6.1)

--D的每个定义应由相同的令牌序列组成;和

如果D的定义满足所有这些要求,那么行为就好像有一个D的单一定义。如果D的定义不满足这些需求,则行为是未定义的。

因此,将"yes"替换为"no"是ODR违规行为,会导致未定义的行为。

对于得到"是"的结果,我可以猜测编译器随机选择一个函数,因为它们必须相同。

另一方面,如果您制作函数static,则在每个翻译单元中都会有不同的本地函数。