如何最好地防止库(源)和应用程序(标题)编译之间的(编译器)标志不匹配?

时间:2014-04-22 09:15:04

标签: c++ c header-files

在实现某个接口时,如头文件中所示,如何最好地防止库实现和头文件之间的危险不匹配?

详细信息:图书馆界面由头文件提供,例如foo.h,以及某些源文件(例如foo.cc)的实现。后者编译为创建库,比如libfoo.so,而前者#include<>由应用程序编辑,与libfoo.so链接。

现在,假设在foo.h

// foo.h
namespace foo {
  class bar
  {
#ifdef SomeOption
    std::int32_t x[2];
#else
    std::int64_t x[2];
#endif
    bar const*ptr;
    /* ... */
  };
}

然后ptr的偏移量为8或16个字节,具体取决于SomeOption(并且sizeof(bar)也不同)。现在,如果使用与SomeOption不同的值编译库而不是应用程序,那么显然会出现严重的问题(对于不知道的内容很难调试)。

解决方案?所以,我提出了以下想法

// foo.h
namespace foo {
  enum { hasSomeOption = 1 };
  int options_flags()
  {
    return 0
#ifdef SomeOption
    | hasSomeOption
#endif
    ;
  }
  class bar
  {
    /* ... as before */ 
    bar(some_args, int);
  public:
    bar(some_args) : bar(some_args, options_flags()) {} // what's option_flags()?
    /* ... */
  };
}

// foo.cc
namespace {
  const int src_flags = options_flags(); // flags used for compiling library source
}
namespace foo {
  bar::bar(some_args, int app_flags)
  {        
    assert(app_flags == src_flags);
    /* ... */
  }
}

认为assert会发现任何不一致之处。但是,这不起作用:编译器似乎优化了我的想法,并且断言永远不会触发,即使SomeOption是 不同的库和应用程序编译。

问题对于此类问题,是否有推荐的最佳方法?

1 个答案:

答案 0 :(得分:1)

我希望有更好的方法,但您可以随时根据选项更改类或命名空间名称,这样如果有人使用了错误的编译器选项,则无法找到该类。

更改命名空间的名称似乎更好 - 在使用调试器时不会引起很多混淆。像这样:

#ifdef SomeOption
    #define foo foo_32bit
#else
    #define foo foo_64bit
#endif

namespace foo
{
 ....
}

我想它会起作用,但肯定是丑陋的。