17

如何FILE *在 C 中转发声明?我通常使用 来执行此操作struct MyType;,但自然这似乎是不可能的。

如果 C 标准或编译器和 C++ 之间的行为不同,这也是令人感兴趣的。

更新0

我为什么要这样做:我要问的是如何转发声明非结构/“typedef'd struct”类型,以便我可以声明指向它的指针。显然void *,在源文件中使用和转换它有点骇人听闻。

4

6 回答 6

25

你不能。该标准只是声明FILE“一种能够记录控制流所需的所有信息的对象类型”;这取决于实现是 a typedefof a struct(无论如何你都不知道它的名字)还是其他东西。

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

于 2010-10-07T14:03:35.583 回答
11

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.

于 2010-10-07T14:01:58.580 回答
6

FILE是一个围绕结构的 typedef,除非通过其专用的 API 函数,否则您不应该过多地探索(就像您不应该使用 WinAPI 句柄后面的数据一样)。

前向声明?

前向声明使人们能够声明一个指向该类型的指针(或在 C++ 上,一个引用),并且只要不使用该符号就可以编译该声明(例如,在您的标头中前向声明一个符号,然后包括标头,其中符号在使用它的源中正确声明)。

因此,前向声明包括:

  • 更快的编译
  • 更少的耦合

Chuck Typedef 与前向声明?

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

所以你不能 forward-declare FILE,也不能 forward-declare std::string。所以你别无选择,只能包括处理它们的标题。

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

前向声明标准符号?

好的部分是,如果符号是“标准”,包含它们的标题应该不会太痛苦。耦合不是什么大问题,如果它会稍微减慢编译速度,即使使用预编译头文件也可以轻松解决问题。

<iosfwd>: 有人想你!

C++ 标准库提供了<iosfwd>头文件。

<iosfwd>如果您只需要前向声明,则可以包含任何(或所有)C++ 流标头,而不是包含任何(或所有)流标头。

于 2010-10-09T09:51:03.517 回答
4

FILE是系统依赖的typedef。您不应该关心实际结构是如何定义甚至命名的。但是你总是可以查看你的/usr/include/stdio.h文件:)

于 2010-10-07T14:02:10.763 回答
0

正如已经指出的,没有可移植的方式来转发声明 FILE 结构或类型定义。

但是,可以将自己的工具的接口更改为依赖纯整数,然后使用fileno函数(也可以通过 获得#include <stdlib.h>)。

详细步骤
0. 找到您当前的界面。例如:
    void myprint(FILE* stream, ...);
1. 使用整数文件描述符 (fd) 而不是FILE*: 2. 使用而不是
    void myprint(int stream_fd, ...);
调用新接口:filenoFILE*
    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在不再需要时关闭资源。通常打开/关闭序列就可以了(如上所示),但是在更复杂的情况下,需要通过使用附加模式等打开文件来调整实现(我们试图避免这种情况)。

于 2016-01-06T10:46:14.703 回答
-3

FILE* 是不透明类型。因此,这在理论上应该是可行的。

typedef struct FILE_impl_but_including_stdio_h_is_best FILE;
于 2010-10-07T14:12:34.080 回答