处理宏重新定义而不修改.h文件... C / C ++语言

时间:2010-04-06 14:42:51

标签: c++ c

背景:

假设我有两个头文件a.h和b.h。

a.h包含:

#define VAR 1

b.h包含:

#define VAR 2

注意:两个宏的名称相同。 假设我有一些文件myFile.c,它包含两个头文件,即a.h和b.h。

当我尝试访问VAR时,我得到VAR的重新定义错误。

为了解决这个问题,我在a.h和b.h文件中插入了#ifndef VAR语句以防止出现此错误。 a.h文件变为

#ifndef VAR
  #define VAR 1
#endif

b.h文件变为

#ifndef VAR
  #define VAR 2
#endif

注意:头文件可以包含多个宏,而不仅仅是一个宏。

问题:

我们假设a.h和b.h文件是从第三方库获得的。这些文件不包含#ifndef VAR语句。

我不允许更改其头文件。

我可以在使用VAR宏的myFile.c或myFile.cpp文件中解决宏'VAR'重定义错误吗?

我知道我#undef VAR可用于取消定义宏VAR。我怎样才能在我的程序中选择性地包含VAR?即在myFile.c代码的第10行我应该能够从ah文件中引用VAR定义,在我的代码的第15行我应该能够从bh文件引用VAR并再次在第18行引用我应该能够引用来自啊文件的VAR。

总之,我能做宏多态吗? 给定头文件的名称,它应该引用该文件中存在的宏定义。

我想过使用命名空间技巧来解决问题。在名称空间中定义第一个头文件,在名称空间第二个中定义第二个头文件。

我尝试定义两个名称空间。第一个命名空间包含#include a.h,第二个命名空间包含b.h.但是,命名空间技巧不适用于宏。当我尝试访问firstns :: VAR时,编译器会报告错误消息。

你能以某种方式提出建议吗?

3 个答案:

答案 0 :(得分:8)

宏扩展发生在preprocessor级别,并且不受命名空间使用的影响。

您想要使用的所有宏都是简单的常量,而不是token concatenation中使用的那些?

如果是这样,那么您可以尝试类似以下内容来桥接预处理器/编译器间隙并保留对ABVAR定义的访问权限,如果它适合您的情况:

// ab_wrapper.h
#include <a.h>
static const int   A_VAR1 = VAR1;
static const char* A_VAR2 = VAR2;
#undef VAR1
#undef VAR2

#include <b.h>
static const int   B_VAR1 = VAR1;
static const char* B_VAR2 = VAR2;

// code.c
#include <ab_wrapper.h>
...
int x = A_VAR1;
int y = B_VAR1;
...

答案 1 :(得分:4)

您可以始终通过自己的专用头文件包含有问题的头文件,您可以在其中添加必要的#ifdef#undef等宏以防止重新定义错误。 E.g。

wrapperToA.h
-----
#ifdef VAR
  #undef VAR
#endif

#include "a.h"

更新: @Vlad在此期间制定了完整的解决方案 - 对他的称赞(和+1: - )

答案 2 :(得分:0)

延伸Peter Torok的答案。

包装第三方组件通常是一个好主意。

有多个步骤:

  • 将标题包装在您自己的标题中,允许控制选项(例如,定义一些预处理标记或根据您自己的标记取消定义其他标记)
  • 创建一个轻量级的外观库,注意隐藏潜在的危险方法,必要时用互斥体包装它们等等......否则只需隐藏详细信息,以便任何更改都不会影响所有代码库。

你对第一个声明更感兴趣,这也是最常见的声明。只需包装它们:

// wrapper/a.h
#ifdef VAR
#undef VAR
#endif // ifdef VAR

#include <3rdparty/a.h>

如果以这种方式系统地包装所有依赖项,那么之后调整就不会有任何问题,因为您可以修改自己的包装器头并重新编译应用程序而不必明确干预第三方标题(这是绝对不推荐的)。

但是有一个问题,你应该仔细检讨......

// 3rdparty/a.h
#define VAR 1

// 3rdparty/aa.h
#include "a.h"
typedef int IntArray[VAR];

// 3rdparty2/b.h
#define VAR 2

这肯定更复杂:)你还需要用undef包装“aa.h”以避免问题......

当然,这意味着你最好不要在代码中的任何地方依赖VAR,因为你知道它的定义可能会根据你包含标题的顺序而改变......