转发声明 FILE *
如何在 C 中转发声明 FILE *
?我通常使用 struct MyType; 来执行此操作,但自然这似乎是不可能的。
如果 C 标准或编译器与 C++ 之间的行为有所不同,这也是令人感兴趣的。
Update0
为什么我想这样做:我要问的是如何转发声明一个非结构/“typedef'd struct”类型,以便我可以声明指向它的指针。显然,使用 void *
并将其转换到源文件中有点hackish。
How do I forward declare FILE *
in C? I normally do this using struct MyType;
, but naturally this doesn't appear to be possible.
If behaviour differs between C standards or compilers and with C++, this is also of interest.
Update0
Why I want to do this aside: What I'm asking is how to forward declare a non-struct/"typedef'd struct" type so that I can declare pointers to it. Obviously using void *
and casting it in the source file is a bit hackish.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
你不能。该标准只是指出
FILE
是“一种能够记录控制流所需的所有信息的对象类型”;这是由实现决定的,这是一个struct
的typedef
(你无论如何都不知道它的名字),还是其他东西。声明
FILE
的唯一可移植方法是使用#include
(或 C++ 中的
)。You can't. The standard just states that
FILE
is "an object type capable of recording all the information needed to control a stream"; it's up to the implementation whether this is atypedef
of astruct
(whose name you don't know anyway), or something else.The only portable way to declare
FILE
is with#include <stdio.h>
(or<cstdio>
in C++).如果您
#include
,您应该获得它的FILE
typedef。这是唯一真正安全且可移植的方法——如果没有类型别名,就不可能有 typedef,并且不能保证FILE
别名是什么类型,因此每个编译器或 libc 或其他任何东西都可以有一个不同的一个。但您需要类型正确,以防有人真正想要#include
,以免不一致的定义导致错误。编辑:
现在我想起来了,可能还有另一种方法。它不是 typedef,而是通过劫持“FILE”的定义来工作的邪恶宏东西。仅出于这个原因我不会推荐它。但它可能适合你的需要。
然后在需要真正的
FILE *
的任何代码中包含该文件之前,#define USES_REAL_FILE_TYPE
,其余代码只会将指针视为无效*
。我不保证这不会把事情搞砸。特别是,在任何情况下,当您想了解此类假类型的真实情况时,它都会中断,并且所有涉及指针的代码可能都需要#define。但是,如果您坚决反对“不必要的”#includes,那么这是您在不干扰 stdio 的情况下获得
FILE *
的唯一方法。您将无法转发声明 typedef。Edit2:
好的,我检查只是为了确定一下。不确定它有多标准,或者你可以用它做什么,但是...
在 Visual C 和 GCC 中都可以工作,但仅在编译 C 代码时。看起来 C++ 标准明确指出,如果没有类型,就不能使用 typedef。但 C 则不然。
然而,它似乎不允许向前声明类型,无论如何在 GCC 中都是不允许的。如果您随后尝试 typedef int FILE;,它会抛出有关 typedef 冲突的错误。然而,VS 似乎允许它,只要它是整数类型。看起来 typedef X 确实意味着 VS 中的 typedef int X(显然,在 C99 中)。不管怎样,GCC 不会让你重做 typedef,即使是完全相同的类型。
If you
#include <stdio.h>
you should get theFILE
typedef with it. That's the only really safe and portable way -- you can't have a typedef without a type to alias, and there's no guarantee about what typeFILE
aliases, so every compiler or libc or whatever can have a different one. But you'd need the type to be correct in case anyone actually wants to#include <stdio.h>
, lest the inconsistent definitions cause an error.Edit:
Now that i think about it, there might be one other way i can think of. It's not a typedef, it's evil macro stuff that works by hijacking the definition of "FILE". I wouldn't recommend it for that reason alone. But it might work for what you need.
Then
#define USES_REAL_FILE_TYPE
before you include the file in any code where you need a realFILE *
, and the rest of the code will just see the pointer as avoid *
.I make no guarantees that this won't mess stuff up. In particular, it will break in any case where you want to know anything real about such a fake type, and all code that touches the pointer may need that #define. But if you're dead set against "unnecessary" #includes, it's the only way you're gonna get a
FILE *
without interfering with stdio. You're not going to be able to forward declare a typedef.Edit2:
OK, i checked just to make sure. Not sure how standard it is,or what you can do with it, but...
works in Visual C and GCC both, but only when compiling C code. It would appear that the C++ standard explicitly says somewhere that you can't have a typedef without a type. The C one, though, doesn't.
However, it doesn't seem to allow a type to be forward declared, not in GCC anyway. If you try to
typedef int FILE;
right afterward, it throws an error about conflicting typedefs. VS, however, seems to allow it, as long as it's to an integer type. Seemstypedef X
really meanstypedef int X
in VS (and apparently, in C99). Either way, GCC won't let you redo the typedef, even to the exact same type.FILE
是一个围绕结构的 typedef,除非通过其专用的 API 函数,否则您不应该过多地探索(就像您不应该使用 WinAPI 句柄后面的数据一样)。前瞻性声明?
前向声明使人们能够声明一个指向该类型的指针(或者在 C++ 上是一个引用),并且只要不使用该符号就可以编译该声明(例如,在标头中前向声明一个符号,然后包含标头,其中符号在使用它的源中正确声明)。
那么,前向声明包含意味着:
ChuckTypedef 与前向声明?typedef 的问题在于它们处理起来很痛苦,因为正如您所发现的,您无法前向声明它们。
因此,您不能前向声明
FILE
,也不能前向声明std::string
。所以你别无选择,只能包含标头来处理它们。(这就是我讨厌来自 C 的 typedef
struct { /* ... */ } MyTypedefedType ;
模式入侵 C++ 代码的原因:它在 C++ 中毫无用处,并且会阻止前向声明。 )前向声明标准符号?
好的部分是,如果符号是“标准”,那么包含它们的标题应该不会太痛苦。耦合并不是什么大问题,如果它会稍微减慢编译速度,即使这样也可以通过使用预编译头来轻松解决。
:有些人想到了你!C++ 标准库提供
标头。如果您只需要前向声明,则可以包含
,而不是包含任何(或全部)C++ 流标头。FILE
is a typedef around a struct you're not supposed to explore too much (like you are not supposed to play with the data behind a WinAPI Handle) unless through its dedicated API function.Forward-declaring?
Forward-declaring enables one to declare a pointer (or on C++, a reference) to the type and having that declaration compile as long as the symbol is not used (for example, forward-declaring a symbol in your header, and then including the header where the symbol is properly declared in the source using it).
So, forward-declaring includes means:
ChuckTypedef vs. Forward-declaring?The problem with typedefs is that they are a pain to handle, because, as you discovered, you can't forward-declare them.
So you can't forward-declare
FILE
, nor you can forward-declarestd::string
. So you have no choice but including the header to handle them.(This is the reason I hate the typedef
struct { /* ... */ } MyTypedefedType ;
pattern from C invading C++ code: It's useless in C++, and it prevents forward-declaration.)Forward-declaring standard symbols?
The good part is that if the symbols are "standards", it should not be too much painful to include their header. The coupling is not so much problem, and if it will slow the compilation somewhat, even that can be made painless through the use of precompiled headers.
<iosfwd>
: Some people thought about you!The C++ standard library offers the
<iosfwd>
header.Instead of including any (or all) the C++ streams headers, you can include
<iosfwd>
if what you need is only forward declaration.FILE
是一个依赖于系统的typedef
。您不应该关心实际结构是如何定义的,甚至是如何命名的。但您始终可以查看您的/usr/include/stdio.h
文件:)FILE
is a system-dependenttypedef
. You are not supposed to care how the actual structure is defined or even named. But you can always look into your/usr/include/stdio.h
file :)正如已经指出的,没有可移植的方法来转发声明 FILE 结构或类型定义。
但是,可以更改自己设施的接口以依赖普通整数,然后使用 fileno 函数(也可以通过
#include
)。详细步骤
0. 找到您当前的界面。例如:
void myprint(FILE* Stream, ...);
1. 使用整数文件描述符 (fd) 代替
FILE*
:void myprint(int stream_fd, ...);
2. 使用
fileno
而不是FILE*
调用新接口:myprint(fileno(stream));
然而,缺点是您的实现(上例中的
myprint
)需要使用以下代码重写文件描述符而不是实际 I/O 例程的 FILE*。重写实现的另一种方法是使用给定的描述符简单地fdopen
一个FILE
。上述内容又会让您思考在哪里“拥有”资源,以便在不再需要时关闭
FILE
。通常打开/关闭顺序就可以了(如上所示),但是在更复杂的情况下,需要通过使用附加模式等打开文件来调整实现(我们试图避免)。As already pointed out, there is no portable way to forward declare the FILE structure or type definition.
However, one can change the interface of the own facility to rely on plain integers, and then use the fileno function (also available via
#include <stdlib.h>
).Detailed steps
0. Locate your current interface. For example:
void myprint(FILE* stream, ...);
1. Use an integer file descriptor (fd) instead of
FILE*
:void myprint(int stream_fd, ...);
2. Call new interface with
fileno
instead ofFILE*
:myprint(fileno(stream));
The disadvantage however is that your implementation (
myprint
in the above example) needs to be rewritten by using a file descriptor instead ofFILE*
for the actual I/O routines. An alternative to rewriting the implementation is to simplyfdopen
aFILE
using the given descriptor.The above in turn causes you thinking about where "to own" the resource in order to close the
FILE
when not needed anymore. Often an open/close sequence is just fine (as shown above), however in more complicated cases one needs to adjust the implementation (which we tried to avoid) by opening the file using append mode, etc.FILE* 是一种不透明类型。因此,这在理论上应该有效。
FILE* is an opaque type. Thus, this should in theory work.