C++ 在代码内部定义指令以分离代码版本

C++ 在代码内部定义指令以分离代码版本,c++,c-preprocessor,preprocessor-directive,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 #defi

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

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

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

#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


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

我以前做过类似的事情。我有一个没有源代码的库,但我有一个头。使用这个库的代码太多了,我无法改变自己

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

所以我做的是:我想出了一些方便的宏,可以将文本转换成其他定义。有两个头文件和一个源文件。例如,假设我想在运行时用傻瓜库替换BarLibrary。在一个名为doublibrary.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
然后,在这个名称空间包装器中重新定义函数调用,如下所示:假设在另一个库中有一个函数
boolbarfun(fooargs…
,您可以将其重新定义为

bool FOO_DECL(BarFun)(fooargs...);
// more FOO_DECL's...
在图书馆
FOO_API
是您常见的
cdecl
类型的垃圾,例如,对于我来说,我正在做
#定义FOO_API WINAPI
。添加类似的声明直到结束,不要忘记关闭名称空间:

#ifdef FOO_HIJACK_NAMESPACE
}
#endif // FOO_HIJACK_NAMESPACE
然后,在foullibrary.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...
等等。最后,再创建一个我喜欢称之为“傻瓜库劫持.h”的头文件:

为每个功能提供一个重新声明、一个重新实施和一个定义。我有大约20个这样的函数,所以我使用正则表达式来生成它们

最后,要全部使用它,在目标代码文件中,包括“傻瓜库劫持.h”作为最后一个
\include
,或者至少在
之后包括“BarLibrary.h”
。然后
\code>将宏
FOO\u HIJACK\u NAMESPACE
定义为某种东西,比如说“FOO”,在预处理器得到它之后,
BarFun
变成
FOO::BarFunFoo


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

预处理器指令在编译时处理。只有在运行时才知道
选项的值。你的想法不可能奏效,因为它会违反因果关系。在你展示的例子中,没有那么多的公共部分。作为两个完全独立、不相关的类型和函数集,它会更好。在您的实际代码中,尝试将常见的、可重用的部分与可变部分分开,可能是使用,或者我正在试图弄清楚这一切意味着什么,我刚刚开始创建两个不同的库,但阅读这篇文章似乎很明显,如果每个库定义相同的符号,我仍然会有冲突。。。还有一些方法是使用#define。。。我真的不知道这是否有效,这就是为什么你在
之后加上“傻瓜库.h”
。\n加上“BarLibrary.h”
。旧的声明仍然存在,为了避免冲突,函数名被更改并放置在另一个命名空间中。一次只能劫持一个源文件中的现有函数调用。这种解决方案非常可怕。把它写在你的简历上,你就可以在美国的任何一家国防承包商那里得到一个高级工程职位。想象一下,回到过去,经历了一大堆无法克服的代码……这只是把它交给了预处理器。它有什么可怕的地方吗?你到处都在使用宏,很难弄清楚代码应该做什么,你引入了与宏相关的臭虫,这些臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的臭名昭著的是,你,由于随之而来的所有维护难题,您似乎使用了至少三种不同的机制来处理不同的代码版本,其中一种机制可以(并将它们与环氧树脂耦合),您建议在这种特殊情况下,第四种机制可能会有所帮助。不要在这些文件上留下你的名字。
#include "FooLibrary.h"
#define BarFun FOO_CALL(BarFun)
// more #define's...