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.
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
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
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.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++).FILE* is an opaque type. Thus, this should in theory work.
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.