What is datatype of FILE? [duplicate]
Asked Answered
M

2

6

What is the data type of FILE in C or in other language?

Is it an integer or structure or having no particular data type?

Malek answered 19/7, 2014 at 18:27 Comment(14)
Why not open up stdio.h in notepadRemedial
I don't understand why this question is being downvoted. I don't know the answer either and would like to learn. And doing man stdio is not an answer. You can answer 90% of the questions on stackoverflow with man xxx.Antonioantonius
@AndreasGrapentin None of the versions of man stdio I looked at had any significant information about what FILE looks like internally. (Which is reasonable, given that it's an implementation detail, but still.)Sapid
+1, I wonder if it would be OK to forward-declare struct FILE; in a header file (to reduce namespace pollution by not including <stdio.h>) and I think it would work on most systems, but the standard don't require it. Definitely a valid question. But what do you mean with “or in other language”? This probably depends on the language and you only tagged it C and C++…Coney
@Coney Actually, that's an interesting question on its own. Is it permissible to, say, declare an array of FILEs? If so, is there anything useful you can do with them?Sapid
@duskwuff Your question has nothing to do with mafso's. Yes you can declare an array of FILEs and yes that is useful.Iatrogenic
@JimBalter Well, one of the major functional differences between having a full definition of the FILE structure in <stdio.h> and having it forward-declared is that you need the full definition to declare a FILE (or an array of them) yourself. So there's the connection.Sapid
Look here What is an opaque value?Normy
@duskwuff Uh, if you're going declare or define something as a FILE ... a single one or an array of them, you need to include stdio.h. So there's no connection at all between your question and mafso's. The answer to mafso's is that such forward declarations are not permitted by the standard.Iatrogenic
Correction: Actually, you cannot and would not declare a FILE or an array of FILEs ... only pointers to FILEs or an array of pointers to FILEs. In all cases you must include stdio.hIatrogenic
@JimBalter: I agree, that you usually don't declare arrays of FILE, but after having a look at the standard it's pretty clear: C99 7.19.1/C11 7.21.1, p.2 The types declared are […]; FILE which is an object type. So, it seems to be possible to declare arrays of FILEs.Coney
@Coney Possible (if you include studio.h) but pointless ... there's nothing you can do with a FILE that you allocate yourself.Iatrogenic
@duskwuff which is really all the information you really need, unless you are a libc core or OS kernel developer :)Nuclei
This question should be re opened, is not duplicated of #3854613 . THe question asks about the datatype of FILE and not what is an opaque value. It happens that FILE is an opaque value . That question is RELATED but not DUPLICATEHonkytonk
S
13

It is what is typically termed an opaque data type, meaning it's typically declared as a simple structure, and then internally in the OS libraries the FILE pointer is cast to the actual date-type of the data-structure that the OS will use access data from a file. A lot of these details are system-specific though, so depending on the OS, the definition may differ.

Siegfried answered 19/7, 2014 at 18:30 Comment(8)
Your suggested implementation of an opaque data type is UB in C ... you can't cast "a simple structure" (whatever that is) to "the actual data-type". And that's not how it's usually implemented ... see duskwuff's answer for an actual example.Iatrogenic
This is implementation dependent, but opaque datatypes are used all the time by libraries... You are using a pointer to an opaque type, and you pass that pointer around but never dereference it directly in your code... Since its a pointer, you can cast it to any type necessarySiegfried
Again, the C standard does not sanction such casts ... they are UB. The way to implement an opaque pointer is to use partial declarations ... forward declaration of a struct type without defining it. The definition is internal to the implementation. No cast is involved.Iatrogenic
P.S. Deduplicator already posted a link to how to do this: https://mcmap.net/q/382725/-what-is-an-opaque-value-in-cIatrogenic
Thank you for the link, and I feel like the link describes what I'm saying, but I guess there are some semantic differences where you feel I'm not exactly explaning things correctly. I'm curious, why is pointer casting considered UB?Siegfried
Read the standard ... you cannot cast a pointer to one struct type to a pointer to another struct type and then dereference it unless one of the structs is the first member of the other. The correct solution is given by paxdiablo at the link, and it is clearly not what you describe because there's no "simple structure" and no casting ... it's the same struct xyzzy in both the caller and the implementation, but only the implementation has access to the members of the struct.Iatrogenic
I did look at paxdiablo's answer, and I still believe that this is not UB. The reason is that according to the standard, you can cast from T* to U* and back to T*, and provided the alignment is correct, the standard specifically states this is not undefined behavior. So the library creates an internal T*, passes the user from the library function an opaque type U* through a cast... The user does not dereference this pointer, but passes it back to the library in another call, at which point the library recasts it to the original internally defined non-opaque T*... That is not UB.Siegfried
"you can cast from T* to U* and back to T*" -- but that's not what you're talking about doing. paxdiablo's method is correct, there's no casting, and I've already wasted my time talking to you. Goodbye.Iatrogenic
S
11

It's a typedef to a structure containing data about the state of the file handle. The exact contents of the structure are system-specific, but on my system (Mac OS X) it's defined as follows:

/*
 * stdio state variables.
 *
 * The following always hold:
 *
 *      if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
 *              _lbfsize is -_bf._size, else _lbfsize is 0
 *      if _flags&__SRD, _w is 0
 *      if _flags&__SWR, _r is 0
 *
 * This ensures that the getc and putc macros (or inline functions) never
 * try to write or read from a file that is in `read' or `write' mode.
 * (Moreover, they can, and do, automatically switch from read mode to
 * write mode, and back, on "r+" and "w+" files.)
 *
 * _lbfsize is used only to make the inline line-buffered output stream
 * code as compact as possible.
 *
 * _ub, _up, and _ur are used when ungetc() pushes back more characters
 * than fit in the current _bf, or when ungetc() pushes back a character
 * that does not match the previous one in _bf.  When this happens,
 * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
 * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
 *
 * NB: see WARNING above before changing the layout of this structure!
 */
typedef struct __sFILE {
        unsigned char *_p;      /* current position in (some) buffer */
        int     _r;             /* read space left for getc() */
        int     _w;             /* write space left for putc() */
        short   _flags;         /* flags, below; this FILE is free if 0 */
        short   _file;          /* fileno, if Unix descriptor, else -1 */
        struct  __sbuf _bf;     /* the buffer (at least 1 byte, if !NULL) */
        int     _lbfsize;       /* 0 or -_bf._size, for inline putc */

        /* operations */
        void    *_cookie;       /* cookie passed to io functions */
        int     (*_close)(void *);
        int     (*_read) (void *, char *, int);
        fpos_t  (*_seek) (void *, fpos_t, int);
        int     (*_write)(void *, const char *, int);

        /* separate buffer for long sequences of ungetc() */
        struct  __sbuf _ub;     /* ungetc buffer */
        struct __sFILEX *_extra; /* additions to FILE to not break ABI */
        int     _ur;            /* saved _r when _r is counting ungetc data */

        /* tricks to meet minimum requirements even when malloc() fails */
        unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
        unsigned char _nbuf[1]; /* guarantee a getc() buffer */

        /* separate buffer for fgetln() when line crosses buffer boundary */
        struct  __sbuf _lb;     /* buffer for fgetln() */

        /* Unix stdio files get aligned to block boundaries on fseek() */
        int     _blksize;       /* stat.st_blksize (may be != _bf._size) */
        fpos_t  _offset;        /* current lseek offset (see WARNING) */
} FILE;

struct __sbuf is a structure used internally by this implementation of stdio to store data buffers, defined as:

struct __sbuf {
        unsigned char   *_base;
        int             _size;
};
Sapid answered 19/7, 2014 at 18:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.