【问题标题】:Forward declaring enum in C++ defined in C在 C 中定义的 C++ 中的前向声明枚举
【发布时间】:2014-02-18 22:58:03
【问题描述】:

我搜索了前向声明,但没有找到任何使我的情况正常的方法。所以这里是:

1) 有一个C-header文件,可以说是大型多组件软件的导出接口,其中包含枚举类型定义

“export.h”:

// This is in "C"!
typedef enum _VM_TYPE {...., ...., ...,} VM_TYPE;

2) C++ 的一部分代码使用该导出。

“cpp_code.cpp”:

// This is in C++
#include "export.h"
#include "cpp_header.hpp"
{ .... using VM_TYPE values to do stuffs....}

“cpp_header.hpp”:

// Need to somehow forward declear VM_TYPE here but how?
Struct VM_INFO {
....
VM_TYPE VType; //I need to add this enum to the struct
....
};

很明显,问题出在 cpp_head.hpp 中,因为它不知道枚举。

我尝试添加到 cpp_header.hpp

typedef enum _VM_TYPE VM_TYPE;

它实际上会起作用。 那么为什么会这样呢?因为它有 C 风格的语法?! 不管怎样,上层“管理层”告诉我不要那样做(“这里是 C++,不是 C”)。

根据当前事物的链接方式,还有其他方法可以完成这项工作吗?他们不想更改/添加包含文件; “枚举类”仅是 C++,对吗?在 cpp_header.hpp 中只添加“enum VM_TYPE”会导致重新定义错误。

有什么想法吗?谢谢。

【问题讨论】:

  • 有什么理由不在 cpp_header 中包含 export.h?似乎它无论如何都依赖于枚举。除非您使用指针/引用,否则您无法使用类/结构来执行此操作。
  • 以下划线和大写字母开头的标识符总是在 C 中保留,包括在标记命名空间中,所以不要使用像 _VM_TYPE 这样的东西。
  • @Andrew: (1) 这些标识符是为 C 保留的,而不是为其他库保留的,所以告诉他们他们写错了 C。 (2) code_header.hpp 也没有问题,因为您首先包含 export.h。当编译器在code_header.hpp 中看到任何内容时,它已经在export.h 中看到了enum 的定义,因为这两个文件本质上都会被复制粘贴到一个翻译单元中,按照顺序你#include他们。因此,当您的编译器到达您的 struct 定义时,它已经看到了您的 enum 的定义。
  • 换句话说,在"export.h" 中包含"export.h" 和在"cpp_code.cpp" 中按顺序包含它们之间基本上没有区别。预处理后,您最终会得到基本相同的代码。

标签: c++ c enums declaration forward


【解决方案1】:

在您的问题中描述的特定情况下,您根本不需要转发声明。你#include 的所有文件在编译开始之前基本上都会被复制粘贴到一个翻译单元中,因为你#include "export.h"之前#include "cpp_header.hpp",那么它就可以工作了,因为当编译器看到struct VM_INFO 的定义时,它已经看到了enum _VM_TYPE 的定义,所以你没有问题。在"cpp_header.hpp" 中包含"export.h" 和在"cpp_code.cpp" 中按顺序包含它们之间基本上没有区别,因为在预处理后您最终会得到基本相同的代码。因此,您在这里要做的就是确保您以正确的顺序获得您的包含。

如果您曾经想在需要访问struct VM_INFO 成员的翻译单元中添加#include "cpp_header.hpp" 不包含 "export.h"(这样就不会将其保留为不完整的类型一个选项)然后"export.h" 的设计很糟糕,您应该将您可能需要的任何内容的定义单独分解为一个新的标题。如果按照 cmets 的建议,您绝对不能这样做并且需要进行次优设计,那么您的下一个最佳选择是拥有两个版本的 "cpp_header.hpp",一个只是重复 enum _VM_TYPE 的定义,另一个是没有。你会#include 在你做的任何翻译单元中的第一个版本#include "export.h"#include 在你做的任何翻译单元中的第二个版本。显然,这种类型的任何代码重复都会在未来引发问题。

此外,以下划线和大写字母开头的名称在 C 中始终保留,因此您真的不应该使用它们。如果 C 的未来版本决定使用_VM_TYPE,那么您将被困在使用过时的 C 版本,或者让所有这些代码中断。

【讨论】:

  • 好的,所以看起来#includes 顺序不是我想/发布的。不太简化的代码是#include "someother.hpp" \\which include "export.h",然后是#include "cpp_header.hpp"。问题是"someother.hpp" 还包括cpp_header.hpp BEFORE "export.h"... 所以顺序颠倒了。必须看看是否可以在不破坏任何现有代码的情况下进行更改...
  • 您的想法应该与我最初发布的内容一致。不幸的是,还有其他部分失败了......即,该组件中的其他文件,只有#include cpp_header.hpp,而不是export.h。所以在编译所有这些文件时,VM_TYPE 是未定义的。
  • 那你需要重新设计。简单而明显的答案就是以反映您需要如何使用其内容的方式编写/修改您的标头,方法是包含 "export.h" 或从 "cpp_header.hpp" 中删除 struct 定义并将其放在单独的标头中.如果出于某些只有您的雇主知道的神秘原因,您不允许正确编写 C,那么您需要按照答案中给出的方式进行某种重复的解决方法,或者您需要放弃您的计划作为您的雇主显然不希望根据他们的设计。
  • Paul,从cpp_header.hpp 移动结构是不可能的,因为很多代码都依赖于它。我认为现在更简单的解决方案是定义一个特定于组件的枚举类型(本质上是相同的),并在 1 个位置将枚举从 export.h 转换为这个特定于组件的枚举类型。然后组件中的其他所有人都可以使用它。
  • 将此标记为正确答案,因为它根据我最初的帖子解决了问题。正如我之前的评论中提到的,需要一个小的重新设计来解决我的特定问题。现在编译好了。谢谢保罗。
【解决方案2】:

枚举不能是前向声明,因为编译器需要知道枚举的大小。底层枚举数是编译器特定的,但通常是 int。您可以将枚举转换为 int 吗?

“我可能而且经常是错的”

【讨论】:

    猜你喜欢
    • 2010-09-09
    • 2011-11-20
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多