【问题标题】:How to avoid that C-header overwrites native C++ type如何避免 C-header 覆盖本机 C++ 类型
【发布时间】:2013-08-22 17:17:55
【问题描述】:

首先我要解释一下我的...

情况

  • 我有这个微控制器代码(普通的旧 C),其中包含 bool.h 和以下内容,因为 stdbool.h 显然不是可用,尤其是不适用于 Visual Studio 2008,这是我目前用于 VC++ 和 C# 的 IDE(见下文):

    #ifndef CUSTOM_BOOL
    #define CUSTOM_BOOL
    
    #ifdef __cplusplus
    extern "C" {
    #endif // #ifdef __cplusplus
    
    #ifndef bool
    #define bool unsigned char
    #endif
    
    #ifndef true
    #define true 1
    #endif
    
    #ifndef false
    #define false 0
    #endif
    
    #ifdef __cplusplus
    }
    #endif // #ifdef __cplusplus
    
    #endif // #ifndef CUSTOM_BOOL
    
  • 现在我需要 C# 项目 中的那个微控制器代码 的功能。这就是为什么我创建了一个中间 Visual C++ 项目,其中包含包装给定微控制器代码的托管类。

  • 由于这个包装器项目 (VC++) 涉及 C 代码,它还必须 #include "bool.h" (但是以间接方式,这意味着包含另一个头文件,它本身包含 bool.h - 但我认为这是一个不重要的细节)。现在这是我的...

问题

由于 bool.h 包含在 VC++ 项目中,并且该项目应提供返回“真实”布尔值的函数(“真实”在这里表示被识别为使用 VC++ 项目时由 C# 调用 bool),不幸的是 VC++ 代码中的 bool 也被预处理器捕获,因此被 unsigned char 替换。现在发生的事情是,C# 最终抱怨不允许从 unsigned char 转换为 bool。这一切都很好,我明白为什么会发生这种情况。所以这是我的...

问题

如何以“干净”的方式解决此问题。我目前的解决方案是,在包含 bool.h 之后,在 VC++ 代码开始之前,我再次取消定义 bool 和朋友,如下所示:

#ifdef bool
#undef bool
#endif

#ifdef true
#undef true
#endif

#ifdef false
#undef false
#endif

它有效,但它打破了我正确的编程方式。有没有合适的方法来解决这个问题?或者问题可能以前发生过?我是否应该定义类似BOOL 而不是bool?根据我在 interwebz 上的搜索,在每个人都同意的 C 项目(不支持 C99)中没有通用的“标准”方式来定义 bool(或 BOOL?)。

【问题讨论】:

  • bool.h 写得不好。它检查__cplusplus,但仍然无用地定义boolfalsetrue。我想说#undefs 是最干净的解决方案。 (并且您不需要 #ifdefs;如果未定义宏,#undef 不会执行任何操作。)

标签: c visual-c++ header boolean c-preprocessor


【解决方案1】:

所以听起来微控制器项目只是组成了一个新的数据类型并将其命名为 bool,现在 bool 是一个关键字(以及 true 和 false),这恰好发生冲突?我的建议(按优先顺序)是:

解决方案 1:修复微控制器项目。 在 bool 上进行全局搜索和替换,并用不那么有争议的东西替换它。可能是 C_Boolean、C_True 和 C_False。不太可能导致任何未来的冲突,并且使用正则表达式相当简单。

解决方案 2:将微控制器项目转换为 C++。 这允许直接使用 bool、true 和 false(作为关键字),您可以删除宏。如果微控制器代码使用与 c++ 不兼容的语法,这可能会很困难。

解决方案 3:做你已经做过的事情。 创建一个包装器包含在包含您的微控制器代码后进行清理。我的代码依赖于重新定义 extern 关键字,这最终成为我唯一安全的方法。不过它很脆弱……当不相关的东西破坏了包含结构时,您可能必须在将来修复它。

另外,我不确定原作者认为 extern "C" 包装器在做什么,但它们对正在定义的宏没有影响。也许你删掉了一些它会影响的东西,但是宏不受链接器名称约定的影响。

【讨论】:

  • 感谢您的努力。 1.这绝对是我也想过的解决方案。但是,对于每个项目都有一种布尔类型也不是很好,尽管它们实际上都用于相同的目的。到 2。不幸的是,这不是一个选择。 3. 好主意,虽然像你说的那样脆弱。感谢您对外部“C”内容的提醒。
  • 如果您有许多不同的微控制器项目正在使用,我更有可能争取#1。创建每个人都用来定义兼容性类型的共享头文件。布尔值,特定大小的类型,标准的大/小端助手等。将它们全部收集到一个标头中,并推动所有微控制器使用该标头及其类型。这里的价值在于您可以在项目之间获得更好的一致性,并且这是每个项目的一次性转换。
  • 是的,完全同意这一点。自从我提出这个问题大约 6 年过去了,我确认这也是我最终在另一家公司工作的方式。
【解决方案2】:

您可以使用运算符将​​返回值(字符)转换为布尔值。例如,在这种情况下,您可以简单地以这种方式比较返回值:

bool b = 0 != functionthatreturnsabolean();

请注意,我没有使用 1,因为布尔值的通常定义是 0 表示 false,否则为其他。

另一种解决方案是简单地使用另一种类型的返回值。整数应该可以正常工作。

编辑:根据注释 - 您还可以简单地创建一个调用这些函数并返回 C# 布尔值的接口。

bool interfacefunction()
{
  return function() != 0;
}

【讨论】:

  • 谢谢,但 C# 项目将成为一个 API,我不希望 API 的用户不得不围绕我的不足进行编程。我肯定想提供一个使用标准 C# bool 的接口。
【解决方案3】:

感谢 Keith Thompson(问题下方的评论)和 Speed8ump 的回答,我有了另一个想法:

bool.h:

#ifndef CUSTOM_BOOL
#define CUSTOM_BOOL

#ifndef __cplusplus

#ifndef bool
#define bool unsigned char
#endif

#ifndef true
#define true 1
#endif

#ifndef false
#define false 0
#endif

#endif // #ifndef __cplusplus
#endif // #ifndef CUSTOM_BOOL

就像一个魅力,我认为它是一个比以前未定义的东西更清洁的解决方案。但是,请随时发表评论或提供更多/更好的答案。

【讨论】:

  • 危险将罗宾逊!请注意,如果您这样做并且还混合了 C 和 C++ 编译单元,两者都将愉快地编译和链接,但是当两者之间共享“bool”变量时,此方法将导致 ABI 不兼容。这可能会导致一些非常微妙的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-10
  • 2015-05-15
  • 1970-01-01
  • 2013-06-02
  • 2019-05-30
  • 1970-01-01
相关资源
最近更新 更多