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

Define directive inside code to separate code versions

本文关键字:代码 分隔 版本 定义 指令      更新时间:2023-10-16

我正在修改别人写的代码。

现有代码包含算法,在两种情况下有效。它们之间的差别很小——只是一些数据类型,有时在处理过程中会多出几行。

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

#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
}

,但调试器跳过,即使在检查"yes"分支时也没有看到定义的ABC。

是否有一种方法来解开这个代码,或者我必须创建明确的单独的路径-复制整个代码?

我以前做过类似的事情。我有一个没有源代码的库,但我有一个头文件。有大量的代码也使用了这个库,远远超出了我自己的能力范围。

嗯,我必须编写另一个库来做与另一个库相同的事情,但使用不同的设备,驱动程序等。你懂的。所以在运行时,我想用我的库代替他们的库,但仍然能够使用旧的(必须向后兼容)。

所以我是这样做的:我想出了一些方便的宏,可以将文本转换为其他定义。有2个头文件和一个源文件。例如,假设我想在运行时用FooLibrary代替BarLibrary selectable。在一个名为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个这样的函数,所以我使用regex为我生成它们。

最后,在目标代码文件中,将#include "FooLibraryHijacked.h"作为最后一个#include,或者至少在#include "BarLibrary.h"之后使用它。然后#defineFOO_HIJACK_NAMESPACE作为某个东西,说"Foo",BarFun在预处理器得到它之后变成Foo::BarFunFoo

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