8

当我读到 K&R 的 The C programming Language 的 pg.176 时,我非常兴奋。我找到了 struct FILE 的所有成员(我正在搜索),知道事情是如何工作的真是太棒了。但是你猜怎么着,gcc 抱怨,错误:'FILE' 没有名为'fd' 的成员。这意味着现在情况发生了变化,我用谷歌搜索但找不到。请帮助,提前谢谢你。

我可以使用 fileno() 来获取文件描述符,但我讨厌在抽象级别上工作。

int
main ( int argc, char **argv ){

    FILE *fp = fopen ("ct.c", "r");
    printf ("%i", fp->fd);

    return 0;
}
4

3 回答 3

15

您需要查看 C 库的源代码。

由于您提到 gcc 和 Linux,您可能正在使用 GNU libc,这当然是免费软件。

该文件说:

/* The opaque type of streams.  This is the definition used elsewhere.  */
typedef struct _IO_FILE __FILE;

这个文件声明了_IO_FILE结构:

struct _IO_FILE {
  int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */

  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

以上来自“真正的”生产质量库的内容可能比 K&R 中使用的示例稍微复杂一些。而且,当然,您不能使用它,因为它是库内部的并且FILE是不透明的类型,正如它所说的那样。

于 2013-06-20T08:52:45.717 回答
1

内部成员根据您的编译器而变化

正如 unwind 所说,您应该查看编译器的库代码(在您的情况下,使用 glibc 的 GCC)。

fileno“函数”实际上是一个宏,在 MinGW(在 stdio.h 中)中定义如下:

    #define fileno(__F) ((__F)->_file)

请注意,MinGW 基于 GCC,不应该有兼容性问题。

由于它是一个宏,您应该能够通过在包含文件夹中搜索“#define fileno”在标准库中找到它。它很可能在 stdio.h 标头中定义。

此外,为了回答您的原始问题,以下是 FILE 的内部成员,如 GCC/MinGW 的 stdio.h 中定义的那样:

    typedef struct _iobuf
    {
        char*   _ptr;
        int _cnt;
        char*   _base;
        int _flag;
        int _file;
        int _charbuf;
        int _bufsiz;
        char*   _tmpfname;
    } FILE;

tldr:在 minGW/GCC 中,使用 fp->_file。如果您使用不同的编译器,请查看帖子的其余部分

于 2018-05-21T17:50:46.463 回答
0

@unwind 的答案很好,但我发现了另一种使用 GCC 的类 Unix 系统的解决方法。

不幸的是,C 不支持反射(C 中的反射支持),但您可以解析 C 预处理器的输出。


shell脚本的源代码

setivolkylany$~/Downloads$ cat script.sh 

# a tempfile for source code on the C programming language
FILE_C=`tempfile`

# a tempfile for preprocessor`s output
FILE_I=`tempfile`

printf "#include \"stdio.h\"\nint main() {return 0;}" > $FILE_C
cpp $FILE_C > $FILE_I

# parse content of the tempfile for preprocessor`s output
# and display only the structure
print_it=false
while read line; do
    if [ "$line" == "struct _IO_FILE {" ]; then
        print_it=true
    fi;
    if [ "$print_it" = true ]; then
        echo $line
    fi;
    if [ "$line" == "};" ]; then
        print_it=false
    fi;
done < $FILE_I

# clean tempfiles
rm $FILE_C $FILE_I

输出

setivolkylany$~/Downloads$ ./script.sh 
struct _IO_FILE {
int _flags;




char* _IO_read_ptr;
char* _IO_read_end;
char* _IO_read_base;
char* _IO_write_base;
char* _IO_write_ptr;
char* _IO_write_end;
char* _IO_buf_base;
char* _IO_buf_end;

char *_IO_save_base;
char *_IO_backup_base;
char *_IO_save_end;

struct _IO_marker *_markers;

struct _IO_FILE *_chain;

int _fileno;



int _flags2;

__off_t _old_offset;



unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];



_IO_lock_t *_lock;
# 293 "/usr/include/libio.h" 3 4
__off64_t _offset;
# 302 "/usr/include/libio.h" 3 4
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
size_t __pad5;

int _mode;

char _unused2[15 chrome-remote-desktop_current_amd64.deb data_structures_algorithms_tutorial.pdf dict-uk_ua-3-5-1.oxt getline.c jquery-3.1.1.min.js ld-linux.so (1).2 ld-linux.so.2 Makefile Portable Microsoft Office 2003.exe Python-3.5.2 script.sh teamviewer_12.0.71510_amd64.deb teamviewer_12.0.71510_i386.deb text_editor.zip sizeof (int) - 4 chrome-remote-desktop_current_amd64.deb data_structures_algorithms_tutorial.pdf dict-uk_ua-3-5-1.oxt getline.c jquery-3.1.1.min.js ld-linux.so (1).2 ld-linux.so.2 Makefile Portable Microsoft Office 2003.exe Python-3.5.2 script.sh teamviewer_12.0.71510_amd64.deb teamviewer_12.0.71510_i386.deb text_editor.zip sizeof (void *) - sizeof (size_t)];

};

这个决定不是很微妙,而是在 C 编程语言中的一次尝试实现反射。

于 2017-03-06T18:44:03.293 回答