转发申报文件*

Mat*_*ner 16 c c++ gcc forward-declaration c89

我如何FILE *在C中转发声明?我通常这样做struct MyType;,但自然这似乎不可能.

如果C标准或编译器与C++之间的行为不同,这也是有意义的.

Update0

为什么我要把这个放在一边:我要问的是如何转发声明一个非struct /"typedef'd结构"类型,以便我可以声明指向它的指针.显然void *在源文件中使用和转换它有点hackish.

Mik*_*our 25

你不能.标准只是声明FILE"能够记录控制流所需的所有信息的对象类型"; 这是由实现这是否是typedefstruct(他的名字你不知道反正),或别的东西.

声明的唯一可移植方式FILE#include <stdio.h>(或<cstdio>在C++中).

  • 如果你绝对不能包含`stdio.h`,唯一的选择是存储指向`void`的指针来代替`FILE *`,然后其他模块必须将它们来回转换为`FILE *`才能使用它们。 (2认同)
  • 我认为`FILE`必然是`typedef`.它不能是`struct`,因为那时它将是`struct FILE`,而不仅仅是`FILE`. (2认同)
  • @Matt:有两个原因:你不了解所有当前和未来的实现,并且没有结构的标准名称(因为标准没有指定它是一个结构体).因此,即使您假设它将是您需要支持的每个实现的结构,也不能转发声明结构,因为您不知道它的名称. (2认同)

cHa*_*Hao 11

如果你#include <stdio.h>应该得到FILEtypedef.这是唯一真正安全且可移植的方式 - 你不能没有类型别名的typedef,并且不能保证FILE别名是什么类型,所以每个编译器或libc或其他什么都可以有不同的别名.但是,如果有人真正想要#include <stdio.h>,你需要这种类型是正确的,以免不一致的定义导致错误.

编辑:

现在我想起来,可能还有另一种我能想到的方式.它不是一个typedef,它是通过劫持"FILE"定义而起作用的邪恶宏观内容.我不会仅仅因为这个原因而推荐它.但它可能适合您的需要.

#ifdef USES_REAL_FILE_TYPE
#include <stdio.h>
#else
#define FILE void
#endif

/* declare your struct here */

#ifndef USES_REAL_FILE_TYPE
#undef FILE
#endif
Run Code Online (Sandbox Code Playgroud)

然后#define USES_REAL_FILE_TYPE在将文件包含在需要实际的任何代码中之前FILE *,其余的代码只会将指针视为a void *.

我不保证这不会弄乱东西.特别是,在任何你想知道关于这种假类型的真实内容的情况下它会破坏,并且所有触及指针的代码都可能需要#define.但是,如果你已经死定了"不必要的"#includes,那么这是你唯一可以在FILE *不干扰stdio 的情况下获得的.你无法转发声明typedef.

EDIT2:

好的,我检查确认.不确定它是多么标准,或者你可以用它做什么,但......

typedef FILE;
Run Code Online (Sandbox Code Playgroud)

在Visual C和GCC中都有效,但在编译C代码时才有效.似乎C++标准明确地说某个地方没有类型就没有typedef.然而,C一个没有.

但是,它似乎不允许向前声明类型,而不是在GCC中.如果你typedef int FILE;之后尝试,它会引发有关冲突的typedef的错误.然而,VS似乎允许它,只要它是一个整数类型.看起来typedef X确实意味着typedef int XVS(显然,在C99中).无论哪种方式,GCC都不会让你重做typedef,即使是完全相同的类型.

  • 因为为了声明`FILE`,你必须知道它背后是什么类型,以免每个实际**#include <stdio.h>`的人得到一个编译错误(因为这两种类型''匹配).但事实上,"FILE"背后的实际类型并未由任何标准指定,因此每个编译器都可能有不同的类型. (4认同)

pae*_*bal 6

FILE 是一个你不应该过多探索的结构的typedef(比如你不应该使用WinAPI句柄背后的数据),除非通过它的专用API函数.

前瞻性声明?

正向声明允许一个人声明一个指针(或C++,一个引用)到该类型,并且只要不使用该符号就编译该声明(例如,在标题中向前声明一个符号,然后包括标头在使用它的源中正确声明的标头).

因此,前向声明包括:

  • 更快的编译
  • 耦合较少

Chuck Typedef vs. Forward-declaring?

typedef的问题在于它们很难处理,因为正如您所发现的那样,您无法前向声明它们.

所以你不能转发声明FILE,也不能转发声明std::string.所以你别无选择,只能包含标题来处理它们.

(这就是我讨厌struct { /* ... */ } MyTypedefedType ;C入侵C++代码中的typedef 模式的原因:它在C++中没用,它阻止了前向声明.)

前向标识符号?

好的部分是,如果符号是"标准",那么包含它们的标题不应该太痛苦.耦合并没有那么多问题,如果它会稍微减慢编译速度,即使通过使用预编译头文件也可以轻松实现.

<iosfwd> :有人在想你!

C++标准库提供<iosfwd>标头.

<iosfwd>如果你需要的只是前向声明,你可以包括,而不是包括任何(或所有)C++流标题.