如何在纯标头库中正确使用宏条件?

问题描述 投票:0回答:1

假设以下代码:

/******* mylib.h *******/
#include <iostream>

class foo
{
public:
    void test()
    {
#ifdef MYDEF
      ::std::cout<<"ZERO\n";
#else
      ::std::cout<<"ONE\n";
#endif
    }
};


/******* module.h *******/
#include "mylib.h"

class module
{
public:
    void test();
}


/******* module.cpp *******/
#include "module.h"

class module
{
public:
    void test()
    {
        foo foo_;
        foo_.test();
    }
};


/******* main.cpp *******/
#define MYDEF
#include "mylib.h"
#include "module.h"

void main()
{
    foo foo_;
    module mod_;

    foo_.test();
    mod_.test();
}

使用

g++
,我独立编译每个实现文件:
module.cpp
-->
module.o

main.cpp
-->
main.o

然后我继续将它们链接在一起,创建

a.out
可执行文件:
module.o
+
main.o
=
a.out

以上所有内容都很好,执行

a.out
打印出:

问题:
考虑到

module.o
main.o
必须对
foo::test()
有不同的定义,因为
main.cpp
定义了
MYDEF
module.cpp
没有定义
MYDEF
,链接器必须选择保留这两个定义之一,因为,正如我们在上面看到的,所有对
foo::test()
的调用都表达相同的行为。链接器如何决定使用哪个
foo::test()
定义?我可以影响这个决定吗?如果我的库还有十几个函数都依赖于
MYDEF
宏怎么办,是否可以保证所有这些函数都会看到相同的
MYDEF
宏定义状态?利用这种行为打破了单一定义规则,但是还应该如何以更好的方式在
foo::test()
中实现例如条件编译的调试打印?

c++ linker macros
1个回答
0
投票

不可能对此进行可靠的影响。

使用不同设置的

MYDEF
编译两个翻译单元是 ODR 违规,因为您的程序包含类
foo
的两个不相同的定义。该程序是 IFNDR(格式错误,无需诊断)并且实际上具有未定义的行为。

这也不仅仅是一个理论上的问题。编译器可以任意内联调用

test
函数,或者在假设
test
具有与翻译单元中可见的相同行为的情况下编译其他函数。

因此,即使您可以影响链接器选择两种实现之一,程序可能仍然不会按照您的预期运行。

© www.soinside.com 2019 - 2024. All rights reserved.