如何FILE *
在 C 中转发声明?我通常使用 来执行此操作struct MyType;
,但自然这似乎是不可能的。
如果 C 标准或编译器和 C++ 之间的行为不同,这也是令人感兴趣的。
更新0
我为什么要这样做:我要问的是如何转发声明非结构/“typedef'd struct”类型,以便我可以声明指向它的指针。显然void *
,在源文件中使用和转换它有点骇人听闻。
如何FILE *
在 C 中转发声明?我通常使用 来执行此操作struct MyType;
,但自然这似乎是不可能的。
如果 C 标准或编译器和 C++ 之间的行为不同,这也是令人感兴趣的。
我为什么要这样做:我要问的是如何转发声明非结构/“typedef'd struct”类型,以便我可以声明指向它的指针。显然void *
,在源文件中使用和转换它有点骇人听闻。
你不能。该标准只是声明FILE
“一种能够记录控制流所需的所有信息的对象类型”;这取决于实现是 a typedef
of a struct
(无论如何你都不知道它的名字)还是其他东西。
声明的唯一可移植方式FILE
是使用#include <stdio.h>
(或<cstdio>
在 C++ 中)。
If you #include <stdio.h>
you should get the FILE
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 type FILE
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.
#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
Then #define USES_REAL_FILE_TYPE
before you include the file in any code where you need a real FILE *
, and the rest of the code will just see the pointer as a void *
.
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...
typedef FILE;
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. Seems typedef X
really means typedef 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++ 上,一个引用),并且只要不使用该符号就可以编译该声明(例如,在您的标头中前向声明一个符号,然后包括标头,其中符号在使用它的源中正确声明)。
因此,前向声明包括:
typedef 的问题在于它们很难处理,因为正如您所发现的,您无法前向声明它们。
所以你不能 forward-declare FILE
,也不能 forward-declare std::string
。所以你别无选择,只能包括处理它们的标题。
(这就是我讨厌struct { /* ... */ } MyTypedefedType ;
C 侵入 C++ 代码中的 typedef 模式的原因:它在 C++ 中没有用,而且它会阻止前向声明。)
好的部分是,如果符号是“标准”,包含它们的标题应该不会太痛苦。耦合不是什么大问题,如果它会稍微减慢编译速度,即使使用预编译头文件也可以轻松解决问题。
<iosfwd>
: 有人想你!C++ 标准库提供了<iosfwd>
头文件。
<iosfwd>
如果您只需要前向声明,则可以包含任何(或所有)C++ 流标头,而不是包含任何(或所有)流标头。
FILE
是系统依赖的typedef
。您不应该关心实际结构是如何定义甚至命名的。但是你总是可以查看你的/usr/include/stdio.h
文件:)
正如已经指出的,没有可移植的方式来转发声明 FILE 结构或类型定义。
但是,可以将自己的工具的接口更改为依赖纯整数,然后使用fileno函数(也可以通过 获得#include <stdlib.h>
)。
详细步骤
0. 找到您当前的界面。例如:
void myprint(FILE* stream, ...);
1. 使用整数文件描述符 (fd) 而不是FILE*
: 2. 使用而不是
void myprint(int stream_fd, ...);
调用新接口:fileno
FILE*
myprint(fileno(stream));
然而,缺点是您的实现(myprint
在上面的示例中)需要使用文件描述符而不是FILE*
实际的 I/O 例程来重写。重写实现的另一种方法是简单地fdopen
使用FILE
给定的描述符。
void myprint(int stream_fd, ...)
{
FILE *const stream = fdopen(stream_fd);
/* your existing implementation follows */
fclose(stream);
}
上述情况反过来又让您考虑在哪里“拥有”资源,以便FILE
在不再需要时关闭资源。通常打开/关闭序列就可以了(如上所示),但是在更复杂的情况下,需要通过使用附加模式等打开文件来调整实现(我们试图避免这种情况)。
FILE* 是不透明类型。因此,这在理论上应该是可行的。
typedef struct FILE_impl_but_including_stdio_h_is_best FILE;