可以在所有翻译单元中进行定义吗?

时间:2019-12-02 13:18:02

标签: c++ c-preprocessor translation-unit

是否可以在所有翻译单元中定义#define或类似的预处理程序定义?

标头实现对于非常小的库很有用,因为所有代码都可以包含和分发为具有以下结构的单个标头:

// library.h

void libFunc(); // forward decl

#ifdef IMPLEMENT_LIBRARY
int libState;
volatile int libVolState; // library state exposed to external processes
void libFunc(){
    // definition
}
#endif

但是,此结构要求用户在将标头仅包含在他们的翻译单元之一之前定义IMPLEMENT_LIBRARY,这意味着它不能放入用户的标头文件中,并且可能会使某些人感到困惑对C ++的编译规则并不完全熟悉。

如果有一种方法可以在所有TU上定义IMPLEMENT_LIBRARY,则可以使用以下方法自动完成

#ifndef IMPLEMENT_LIBRARY
#defineToAllUnits IMPLEMENT_LIBRARY
// library state
// definitions
#endif

这种机制是否存在,或者当前的单头系统是否会达到最佳状态?

2 个答案:

答案 0 :(得分:2)

对于此用例,您可能根本不应该使用宏定义。如果要在库用户的TU中定义函数,则可以使用内联函数。内联函数可以在一个以上的TU中定义(只要定义相同):

// library.h
inline void libFunc(){
    // definition
}

另一种方法是分别编译库,并让库的用户与其链接,而不是将定义包含在自己的TU中。


关于问题本身

  

是否可以在所有翻译单元中定义#define或类似的预处理程序定义?

可以在多个TU中#define预处理程序宏:

// a.cpp
#define foo a

// b.cpp
#define foo b

如果要使定义与定义它的所有TU匹配,则可以将宏定义放入头文件中,并包括以下内容:

// h.hpp
#define foo h

// a.cpp
#include "h.hpp"

// b.cpp
#include "h.hpp"

不可能将一个TU的定义“注入”到其他TU,因此不可能有等效的“ #defineToAllUnits”。 通常可以从编译器调用gcc a.cpp b.cpp -Dfoo=h中“注入”宏定义。但是,我认为这对您的用例没有帮助。

答案 1 :(得分:2)

有些编译单元很可能已经在包含#defineToAllUnits的单元之前被编译了,所以这是不可能的。

在实践中,通常可以通过使用构建系统将-DIMPLEMENTAT_LIBRARY选项传递给编译器(或等效语法)来解决您的问题。尝试通过多个定义实现广泛的可移植性时,另一种常见的可能性是在每个地方都包含config.h这样的配置头。该标头可以在配置时自动生成。

您还可以通过使用inline函数和变量来避免侵犯ODR。