【问题标题】:How to make sure different C++ code base using the same macro?如何使用相同的宏确保不同的 C++ 代码库?
【发布时间】:2017-08-25 03:18:32
【问题描述】:

我们正在开发两个 C++ 代码库,我们称之为 ABA 是作为库的构建,并将头文件.h.a文件分发到B

假设A中有Lock.h文件如下:

// Lock.h in code base A
class Lock {
    ... ...
#ifdef TRACK_THREAD_OWNER_FOR_DEBUG
    virtual int GetLockOwner();
#endif
    ... ...
private:
    CriticalSection section;
#ifdef TRACK_THREAD_OWNER_FOR_DEBUG
    int threadOwner;
#endif
};

// Caller.cc in code base B
#include "xxx/xxx/Lock.h"
Lock lockObject;
lockObject.Lock();

在代码库 A 中,我们默认启用TRACK_THREAD_OWNER_FOR_DEBUG,并且可能会在最终发布日之前对其进行更改。

我们遇到了一些严重的错误,因为TRACK_THREAD_OWNER_FOR_DEBUGAB 中不同,并且由于 sizeof(Lock) 在两个库中不同而导致内存损坏。

那么如何避免这个错误呢?如果构建宏TRACK_THREAD_OWNER_FOR_DEBUG在两个项目中不同,我们可以在构建caller.cc文件时触发编译器错误吗?

【问题讨论】:

    标签: c++ macros


    【解决方案1】:

    不可能将其变成编译器错误,但是通过导出一些名称取决于当前定义的宏的符号,应该可以将其变成合理清晰的链接器错误。例如使用静态保护变量:

    //  Foo.hpp - library header file
    #pragma once
    
    class Foo
    {
        public: Foo();
    #ifdef IMPORTANT_CONDITION
        int m_field;
    #endif
    };
    
    class ConditionGuard
    {
        public:
        ConditionGuard(void) noexcept
        {
        #ifdef IMPORTANT_CONDITION
            CONDITION_ON();
        #else
            CONDITION_OFF();
        #endif
        }
    
    #ifdef IMPORTANT_CONDITION
        private: static void CONDITION_ON(void);
    #else
        private: static void CONDITION_OFF(void);
    #endif
    };
    
    static ConditionGuard const condition_guard{};
    
    // Foo.cpp - library implementation file 
    #include "Foo.hpp"
    
    Foo::Foo(void) {}
    
    #ifdef IMPORTANT_CONDITION
    void ConditionGuard::CONDITION_ON(void) {}
    #else
    void ConditionGuard::CONDITION_OFF(void) {}
    #endif
    

    现在,当用户代码包含库头 Foo.hpp 时,它还将触发 condition_guard 静态变量的构造,该静态变量将根据受保护的条件调用库函数。因此,如果存在包含Foo.hpp 的翻译单元,其中IMPORTANT_CONDITION 的定义与编译库中的定义不同,则缺少CONDITION_ONCONDITION_OFF 将出现链接器错误。 CONDITION_ONCONDITION_OFF 函数名称应包含错误文本。

    【讨论】:

      【解决方案2】:

      一种选择是将 A 的完整代码包含到项目 B 中。您想通过将 A 编译到静态库中来做什么?

      我认为您最好的选择是根据目标生成不同的 .a 文件。即设置 TRACK_THREAD_OWNER_FOR_DEBUG 时为 libA_debug.a,未设置时为 libA.a。

      然后您可以根据您是在编译调试版本还是发布版本,将库设置为链接 B。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-19
        • 1970-01-01
        • 2018-12-04
        • 2011-08-06
        • 1970-01-01
        • 2018-01-29
        • 1970-01-01
        相关资源
        最近更新 更多