使用prepocessor的#ifdef更改变量类型

时间:2014-05-20 15:17:41

标签: c++ c-preprocessor

我有两个应用程序' server'和'客户'它依赖于很多相同的代码。 他们需要在与控制台交互的方式上表现不同。我想在两种不同的情况下包括两个不同的类,而不是编写一个处理这两种情况的类。现在,在Globals.h和Globals.cpp中我这样做:

Globals.h:

#ifdef SERVER
extern ConsoleUI ui;
#else
extern Logger ui;
#endif

Globals.cpp:

#include "Globals.h"
#ifdef SERVER
ConsoleUI ui;
#else
Logger ui;
#endif

(我也在标题中包含了警卫,但是将它们留在了这里)。

在服务器的主文件中,我定义:

#define SERVER

在客户的主文件中,我使用:

#define CLIENT

然而,他们两个最终都创建了一个Logger ui而不是ConsoleUI ui。 我知道这是因为服务器试图调用一个存在于ConsoleUI和segfaults中的函数,因为出于某种原因他的" ui"属于" Logger"。

我确实认识到更清洁的方法可能是将Globals分成GlobalsClient.h / .cpp和GlobalsServer.h / .cpp,但我想理解为什么上面的代码不起作用。

希望以前没有问过,我搜索的所有内容都没有给我任何有用的点击。

3 个答案:

答案 0 :(得分:2)

您拥有的代码可能失败的原因是,如果您执行#define SERVER之类的操作会创建SERVER符号。如果您在其他地方也有#define CLIENT,那么以下内容:

#include "Globals.h"
#ifdef SERVER
ConsoleUI ui;
#else
Logger ui;
#endif

实际上是ifdef SERVER分支,可能不是您想要的。

为了按照您希望的方式进行条件编译,您需要为服务器编译一次,对客户端使用来自命令行的#define编译一次。执行此操作的标志通常为-D

因此,使用#ifdef方法为服务器进行编译,您可以执行类似

的操作
g++ -DSERVER -o server_output_name

并为客户提供:

g++ -DCLIENT -o client_output_name

然而,重要的是要意识到一般来说,有更好的方法可以在c ++中实现你想要的东西。具体来说,你想让语言为你做类型检查,而不是依赖于相对而言不安全的#34;预处理。如果有很多公共代码,那么创建一个包含该代码的基类并具有两个实现非公共代码的派生类呢?

类似的东西:

class UIBase{

protected:
 //all the common code
};


class UIServer : public UIBase{
//server specific code and implementation
};

class UIClient : public UIBase{
//client specific code and implementation
};

通过这种方式,您可以根据类型创建对象,并使用c ++语言确保根据上下文调用正确的代码。您可以通过#define方法获得某种类型的安全性。

答案 1 :(得分:1)

问题可能是您没有始终如一地定义SERVERCLIENT。将Globals.h更改为:

#ifdef SERVER
#ifdef CLIENT
#error "Both CLIENT and SERVER defined!"
#endif
#define ui ServerUI
extern ConsoleUI ui;
#elif defined(CLIENT)
#define ui ClientUI
extern Logger ui;
#else
#error "Neither CLIENT nor SERVER defined!"
#endif

现在,如果您缺少SERVER和/或CLIENT的其他设置或其他设置,您将收到编译器或链接器错误,而不是运行时崩溃。

答案 2 :(得分:0)

确保在主cpp中包含'Globals.h'之前加上'#define SERVER'。