在代码中定义指令以分隔代码版本

时间:2014-08-18 19:56:42

标签: c++ c-preprocessor preprocessor-directive

我正在修改其他人编写的代码。

现有代码包含算法,适用于两种情况。差异很小 - 一些数据类型,有时还有一些额外的行处理。

原始代码将所有内容设置为

#define ABC

#ifdef ABC
typedef struct {
    unsigned char a, b, c;
} MyStruct;
#else  
typedef unsigned char MyStruct;
#endif 

#if defined(ABC)
#define SIZE1 3
#else  
#define SIZE1 2
#endif 

typedef struct {
    MyStructtable[SIZE1];
} MyStructA;

void MyMethod(){
   statement1;
   #if defined(ABC)
   staement2;
   #endif
}

它的工作原理......如果在源代码中做出选择,但是我试图让用户选择使用一个版本或另一个版本,并且最难分开代码。

我可以为每个版本创建一套完整的文件。我遇到的问题:

由于存在复杂的算法,因此将算法保存在一个位置是有意义的...如果在一个版本而不是其他版本中进行更改,则复制代码可能会导致错误。

我试图做一些类型

if(option)
{
  #define ABC
} 
else
{
  #undef ABC
}

但是调试器会跳过并且看不到定义的ABC,即使是在过了"是"分支。

有没有办法解开这段代码,还是我必须创建清晰的单独路径 - 复制整个代码?

1 个答案:

答案 0 :(得分:1)

之前我做过类似的事情。我有一个我没有源代码的库,但我确实有一个标题。有很多代码使用这个库,也比我自己改变的方式更多。

我必须编写另一个库来编写与另一个库相同的东西,但是使用不同的设备,驱动程序等。你得到了图片。所以在运行时我想用我的库代替它们,但仍然能够使用旧的(必须向后兼容)。

所以我做的是:我提出了一些方便的宏,可以将文本转换为其他定义。有2个头文件和一个源文件。例如,假设我想在运行时将FooLibrary替换为可选择的BarLibrary。在一个名为FooLibrary.h的头文件中:

// don't ask me why, but two levels of indirection is necessary
// to pull off a certain concatenation
// this I got from another question on SO
#define CAT(x, y) x ## y
#define cat(x, y) CAT(x, y)

#ifdef FOO_HIJACK_NAMESPACE

// library init functions
bool ShouldHijack();
void SetHijack(bool yn);

// handy-dandy function-changing macros
#define FOO_FN_NAME(X) cat(X, FOO_HIJACK_NAMESPACE)
#define FOO_FN_NAME_NS(X) FOO_HIJACK_NAMESPACE :: FOO_FN_NAME(X)

#define FOO_DECL(X) FOO_API FOO_FN_NAME(X)
#define FOO_IMPL(X) FOO_API FOO_FN_NAME_NS(X)
#define FOO_CALL(X) (ShouldHijack() ? FOO_FN_NAME_NS(X) : X)

namespace FOO_HIJACK_NAMESPACE {
#else

#define FOO_DECL(X) X
#define FOO_IMPL(X) X
#define FOO_CALL(X) X

#endif // FOO_HIJACK_NAMESPACE

然后,在这个命名空间包装器中你重新定义函数调用,如下所示:在你的另一个库中有一个函数bool BarFun(fooargs...),你可以将它重新定义为

bool FOO_DECL(BarFun)(fooargs...);
// more FOO_DECL's...

在FooLibrary.h中。 FOO_API是您常用的cdecl类垃圾,对我来说,我正在做#define FOO_API WINAPI。添加类似的声明直到最后,不要忘记关闭命名空间:

#ifdef FOO_HIJACK_NAMESPACE
}
#endif // FOO_HIJACK_NAMESPACE

然后,在FooLibrary.cpp中,您提供了类似的实现:

#include "FooLibrary.h"

// hijack
static bool bShouldHijack = false;
bool ShouldHijack() { return bShouldHijack; }
void SetHijack(bool yn) { bShouldHijack = yn; }

bool FOO_IMPL(BarFun)(fooargs...)
{
    // your implementation here...
}
// more FOO_IMPL's...

等等。最后,你再制作一个我想调用的头文件" FooLibraryHijacked.h":

#include "FooLibrary.h"
#define BarFun FOO_CALL(BarFun)
// more #define's...

为每个函数提供一个重新声明,一个重新实现和一个#define。我有20个这样的函数,所以我使用正则表达式为我生成它们。

最后,要在目标代码文件中使用它,#include "FooLibraryHijacked.h"作为上一个#include,或者至少在#include "BarLibrary.h"之后。然后#defineFOO_HIJACK_NAMESPACE作为内容,在预处理器获得它之后,说" Foo"和BarFun变为Foo::BarFunFoo

现在如何使用单独的类型定义来实现它将会很有趣。如果应用程序代码只将变量从一个函数传递到另一个函数,也许你可以使用不透明指针。