我正在修改别人写的代码。
现有代码包含算法,适用于两种情况。差别很小——一些数据类型,有时在处理过程中有一些额外的行。
原始代码将所有内容设置为
#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
}
但调试器会跳过并且即使在越过"is"分支时也看不到定义的 ABC。
有没有办法解开这段代码,或者我是否必须创建清晰的单独路径 - 复制整个代码?
最佳答案
我以前做过这样的事情。我有一个没有源代码的库,但我有一个标题。也有大量代码使用了这个库,远远超出了我自己可以更改的范围。
好吧,我不得不编写另一个库来完成与另一个库相同的事情,但使用不同的设备、驱动程序等。你明白了。所以在运行时我想用我的库替换他们的,但仍然能够使用旧的(必须向后兼容)。
所以我所做的是:我想出了一些方便的宏,可以将文本转换为其他定义。有 2 个头文件和 1 个源文件。例如,假设我想用 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"
。然后 #define
宏 FOO_HIJACK_NAMESPACE
作为某种东西,说“Foo”,然后 BarFun
变成 Foo::BarFunFoo
预处理器会掌握它。
现在如何使用单独的类型定义来做到这一点将很有趣。如果应用程序代码仅将变量从一个函数传递到另一个函数,或许您可以使用不透明指针。
关于c++ - 在代码中定义指令以分隔代码版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25371066/