【问题标题】:Is there a way to workaround a #define introduced by a vendor?有没有办法解决供应商引入的#define?
【发布时间】:2013-10-23 01:09:26
【问题描述】:

因此,我们使用的供应商提供了一个库(主要用于 C,具有一些 C++ 支持),它执行以下操作:

#ifndef int64_t
#define int64_t s_int64
#endif
#ifndef int32_t
#define int32_t s_int32
#endif
#ifndef int16_t
#define int16_t s_int16
#endif
#ifndef int8_t
#define int8_t  s_int8
#endif

在他们图书馆深处的一个标题中。现在的问题是,一旦他们的库包含在简单的 C++11 代码中,例如:

#include <iostream>

#include <vendor/library.h>

int main(void)
{
  std::int32_t std_i = 0;
  return std_i;
}

立即出现编译器错误,(s_int32 不在std:: 中)。所以问题是,除了唠叨供应商来解决这个问题,有没有办法在我们的代码中解决这个问题? (顺便说一句。我尝试过的东西,#include &lt;cstdint&gt; before 他们的标题,没有运气;extern "C" 包装器,没有运气。标题安装在/usr/include/ 所以无法控制包含顺序我也猜一猜……)

【问题讨论】:

  • 不要在代码中包含此类标头。他们污染它。不要使用供应商的代码。
  • @DanielDaranas,如果他们的库必须用于访问硬件,这不是一个选项! ://
  • 可以在不使用标题的情况下使用该库。库由链接器包含,头由预处理器解析;只需复制标题,编辑它,包括本地副本。毕竟是 C,而不是 Java!
  • @vaxquis,对不起,但这是一个非常愚蠢的建议,所以我必须在供应商头文件发生变化时修补和维护它们?真是浪费时间……
  • 我不是说你应该这样做,我说这显然是可能。 Daniel Daranas 提供了一个有效的观点;你说“这不是一个选项”提供了无效的理由,我提供了一个选项,证明你的理由是错误的;您显然不明白您不能同时使您的代码依赖于供应商和可移植。您的问题主要是您没有通过接受供应商的解决方案来获得它,您基本上同意其编程合同;围绕此联系人创建解决方法是您不同意它的标志 - 但是您使用它而不是尝试创建一个更好的解决方法。

标签: c++ c c++11


【解决方案1】:

预处理器有一个聪明的属性:在替换宏时递归被阻止了!因此,您可以这样定义它们:

#define int64_t int64_t
#define int32_t int32_t
#define int16_t int16_t
#define int8_t int8_t

之前包括供应商的标头。这样它们就不会被重新定义(因为它们正在使用#ifndef)并且它们在您的其余代码中保持其预期含义。

【讨论】:

  • 这里唯一的问题是供应商的标题是否假定int64_t 实际上是他们自己的s_int64。根据s_int64 的实际情况,在调用其库函数时,它最终可能不会映射到正确的类型。它可能只是一个名字,但你永远不知道 :)
  • @icabod 如果他们真的这么认为,他们不应该使用#ifndef。但是好的,我只是指出一个选项,只有您可以决定它是否适合您的环境。
  • 确实,唯一真正的解决方案是让供应商修复他们的东西 - 用你的钱包投票:)
  • @icabod,不幸的是,这是他们企业产品的操作系统版本,谢天谢地,他们的服务台非常棒,刚刚收到了修复此问题的标头补丁 - 我想很多其他客户也在抱怨。 .. :D 现在我的问题是接受哪个答案...因为所有三个(有投票)都贡献了部分解决方案.. :)
  • 我建议接受这个答案,因为它更接近你实际解决问题的方法,尽管是通过命令行而不是源代码 - 我自己的答案添加了你可能没有的东西需要。看着我,扔掉代表!
【解决方案2】:

如果不查看文件中的其他内容,很难找到一个 100% 有效的解决方案。

但是,您可以尝试以下一个想法(注意 - 我在我的编译器中模糊地尝试过这个想法,但我不保证它会在任何其他版本中工作)。

创建一个包含它们的定义的文件,但作为 typedefs:

typedef s_int64 int64_t;
...

然后,一些编译器允许您在命令行上指定要包含在任何其他文件之前的文件...例如,gcc 具有-include 开关,因此您指定包含此文件。

然后,同样在您的命令行上,您也可以为自己定义该映射:

-Dint64_t=int64_t

甚至将定义放在上面的文件中:

#define int64_t int64_t

结果是,理论上,#defines 不会干扰任何其他代码(他们不应该做任何事情 - 虽然我不确定你最终是否可以递归扩展?)。当您创建了正确类型的 typedef 时,供应商代码应该仍然有效。

您将 typedef 放入强制包含的文件中的原因是,您希望确保它首先被包含在内。

那么你应该让供应商更新他们的代码以使用typedef。您是客户,他们想向您推销产品。

所有的理论头脑。

【讨论】:

  • 实际上,您在编译行的定义上的点实际上可以解决问题!我们遇到的问题是我们有几个旧版本的代码,其中包括供应商提供的这个库。我们无法重新发布那些旧版本,但是我们可以更改编译行,这个 hack 可能暂时有效,并允许我们使用较新版本的库..
  • 正如我在评论中提到的,在编译行中添加一系列-D... 可以修复编译器错误。这意味着我们的旧版本和任何新编译都可以正常工作......因此,我会接受这个答案......
【解决方案3】:

他们正在使用#ifndef 宏,这意味着:如果未定义,则值为 ...

先用你的价值观定义它:

#define int64_t (xx)
#define int32_t (xx)
#define int16_t (xx)
#define int8_t  (xx)

【讨论】:

  • 问题是那些应该是类型,而不是定义的常量。这就像说#ifndef int
  • 我怀疑这些自己的宏会比供应商定义的宏有用得多。
  • #define int64_t int64_t 怎么样?并且对于每种类型都类似?那么他们将被定义为他们自己,一切都应该工作......
  • 尽管#define 保留名称在技术上是未定义的行为,但#define int64_t int64_t 几乎肯定会让一切正常。当然,假设您的实现确实提供了int64_t,并且您包含“stdint.h”。
【解决方案4】:

您可以取消定义它们的定义。

#undef int64_t
#undef int32_t
#undef int16_t
#undef int8_t

【讨论】:

  • ...呃...可怕,但别无选择...:/
  • @EliasVanOotegem 他们不是。在普通的 ol' C 中,它是必要的邪恶。
  • @Elias:这些肯定不是很好,这就是提问者对它们有问题的原因。
  • @EliasVanOotegem:有人可能会争辩说命名整数常量的宏也不是很好,您可以/应该使用枚举。宏就像对魔法的信仰,您可以使用它们来处理您无法(还)正确处理的任何事情;-)
  • 您可以通过制作自己的头文件来缓解 undef 的痛苦:myVendor.h,看起来像:#include "vendor.h" #undef int64_t #undef int32_t, etc...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 2022-01-21
  • 2011-03-19
  • 2018-05-16
  • 1970-01-01
  • 2015-05-26
相关资源
最近更新 更多