What do FILE struct members mean exactly in C? - c

typedef struct _iobuf{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
} FILE;
I try to print them but I don't understand what they mean.
Here What exactly is the FILE keyword in C? He said "Some believe that nobody in their right mind should make use of the internals of this structure." but he didn't explain what they mean.

Look at the source code for your system's run-time libraries that implement the FILE-based IO calls if you want to know what those fields mean.
If you write code that depends on using those fields, it will be non-portable at best, utterly wrong at worst, and definitely easy to break. For example, on Solaris there are at least three different implementations of the FILE structure in just the normal libc runtime libraries, and one of those implementations (the 64-bit one) is opaque and you can't access any of the fields. Simply changing compiler flags changes which FILE structure your code uses.
And that's just one one version of a single OS.

_iobuf::_file can be used to get the internal file number, useful for functions that require the file no. Ex: _fstat().

Related

Is there any way to print all nested struct size in C?

I have a case where there are multiple structures contained in one structure.
Small example:
typedef struct data {
int x;
} data_t;
typedef struct info {
data_t data_element[10];
int y;
} info_t
Is there any way to print all struct sizes which are members of info_t?
Not without knowing what those types are. C does not have reflection (the way that java or c# do, for example).
If you do know the types it's simply a matter of using sizeof and a print function.
This is impossible using the C language alone, since it does not provide for such introspection. All you can do is iterate over the struct members and print their sizes.
That said, a decade ago, I had to do just this for large complicated struct of several hundred members. I finally got the required information from parsing the debugging section of the object file. I don't have details anymore, but you will need to compile with the -g flag and then dump debug output with an appropriate tool. Try looking at the readelf and objdump utilities and manual pages.

trigger function before file write operation

Let say we have a function:
void persist_result(FILE* to, unsigned char* b, int b_len) {...}
which would save some result in the given FILE* to.
Now I would like to get the data before the data is written to to, do something with it (assume encrypt it, etc..) and then call the actual IO operation, directly or indirectly.
One solution could be setting a buffer, but I don't know how to trigger my method for the encryption operation.
Also I was thinking to get some handle of file in memory, but don't know if there is any ISO way to do that?
Or any better solution?
Consider the following:
Size of the data need to be written by the persist_result is unknown, it could be 1 or more bytes.
I cannot change the source of persist_result.
No C++; it must be a portable C solution.
What you are looking for is the Observer Pattern.
When your function is called, actually you can first capture that call, do whatever you prefer and then continue with what you were doing. You could implement it in C using pointer to functions.
You can get inspiration from the following example
There is no way to capture every operation in standard C without changing the calls. Things like encryption need context (like key) to work; that complicates life in general, but maybe persist_result() handles that automatically. How will you handle things like fseek() or rewind()?
I think you are in for a world of pain unless you write your I/O operations to a non-standard C API that allows you to do what's necessary cleanly. For example, your code might be written to call functions such as pr_fwrite(), pr_putc(), pr_fprintf(), pr_vfprintf(), pr_fseek(), pr_rewind(), etc — you probably wouldn't be applying this to either stdin or stdout — and have those do what's necessary.
If I were going to try this, I'd adopt prefixes (pr_ and PR) and create a header "prstdio.h" to be used in place of, or in addition to, <stdio.h>. It could contain (along with comments and header guards, etc):
#include <stdarg.h>
// No need for #include <stdio.h>
typedef struct PRFILE PRFILE;
extern PRFILE *pr_fopen(const char *name, const char *mode);
extern int pr_fclose(PRFILE *fp);
extern int pr_fputc(char c, PRFILE *fp);
extern size_t pr_fwrite(const void *buffer, size_t size, size_t number, PRFILE *fp);
extern int pr_fprintf(PRFILE *fp, char *fmt, ...);
extern int pr_vfprintf(PRFILE *fp, char *fmt, va_list args);
extern int pr_fseek(PRFILE *fp, long offset, int whence);
extern void pr_rewind(PRFILE *fp);
…
and all the existing I/O calls that need to work with the persist_result() function would be written to use the prstdio.h interface instead. In your implementation file, you actually define the structure struct PRFILE, which would include a FILE * member plus any other information you need. You then write those pr_* functions to do what's necessary, and your code that needs to persist results is changed to call the pr_* functions (and use the PRFILE * type) whenever you currently use the stdio.h functions.
This has the merit of being simply compliant with the C standard and can be made portable. Further, the changes to existing code that needs to use the 'persistent result' library are very systematic.
In a comment to the main question — originally responding to a now-deleted comment of mine (the contents of which are now in this answer) — the OP asked:
I need to do the encryption operation before the plain data write operation. The encryption context is ready for work. I was thinking using the disk on memory, but is it ISO and can be used in Android NDK and iOS too?
Your discussion so far is in terms of encrypting and writing the data. Don't forget the other half of the I/O equation — reading and decrypting the data. You'd need appropriate input functions in the header to be able to handle that. The pr_ungetc() function could cause some interesting discussions.
The scheme outlined here will be usable on other systems where you can write the C code. It doesn't rely on anything non-standard. This is a reasonable way of achieving data hiding in C. Only the implementation files for the prstdio library need know anything about the internals of the PRFILE structure.
Since 'disk in memory' is not part of standard C, any code using such a concept must be using non-standard C. You'd need to consider carefully what it means for portability, etc. Nevertheless, the external interface for the prstdio library could be much the same as described here, except that you might need one or more control functions to manipulate the placement of the data in memory. Or you might modify pr_fopen() to take extra arguments which control the memory management. That would be your decision. The general I/O interface need not change, though.

Implementing shared library / module - argument struct not in headers

I am trying to implement a custom locking library for LVM. Setting locking_type to external (2) in lvm.conf and providing a shared library implementing the required functions seems enough and relatively simple, in theory.
Looking into this I started with the sources for LVM2, specifically the external locking mechanism implementation, which can be found here.
Basically, what I figured out that I need to do is to implement functions with the headers described like this:
static void (*_reset_fn) (void) = NULL;
static void (*_end_fn) (void) = NULL;
static int (*_lock_fn) (struct cmd_context * cmd, const char *resource, uint32_t flags) = NULL;
static int (*_init_fn) (int type, struct dm_config_tree * cft, uint32_t *flags) = NULL;
static int (*_lock_query_fn) (const char *resource, int *mode) = NULL;
Now, everything peachy up to this point. However, looking at the _lock_fn definition, it takes a pointer to struct cmd_context as first argument. That struct can easily be found in the LVM2 sources (and it is a fairly complex one!), but it is not inside the headers exposed by the package as an API (eg. the lvm2-devel package in RHEL7). As I imagine (I am definitely not the best C programmer around), since that struct is supposed to be used by external libraries, it is mandatory that it should be in the headers.
Am I thinking this wrong or is it just a "bug" and I should discuss with LVM2 developers? Are there any workarounds, other than copy/pasting that struct and all other types that it depends on to a header file in my project? Doing this "workaround", does it break the GNU GPL license in any way?
The source file you linked, indirectly includes the config.h header which has this line:
struct cmd_context;
This tells the C compiler that there is a struct with that name. That's all the compiler needs to know to generate correct machine code.
If you were to access members of that struct or directly create an object of it, you would get errors thrown your way because the compiler doesn't know size or members of the struct.
But as long you use it as an opaque data type passing a known-size pointer to it in and out of functions, you are ok. This is called forward declaration and is a primary way of achieving encapsulation in C (check stdio's FILE).

When to decide to use typedef's data types or C's built-in standard data types

gcc 4.7.2
c89
Hello,
I am using the Apache Portable Runtime and looking at their typedef's
typedef short apr_int16_t
typedef int apr_int16_t
typedef size_t apr_size_t /* This is basically the same, so what's the point */
etc.
So what is the point of all this?
When should you decided to use C's built-in standard data types or typedef's data types?
I just gave a example using the APR. However, I am also speaking generally as well. There is also the stdint.h header file that typedef's data types.
Many thanks for any suggestions,
In my opinion, it is better to have custom defined data types for native data types of the system as it helps in clearly distingushing the size of the types.
For Ex: A long may be 32 bit or 64 bit depending on the machine in which your code runs and the way it has been built. But, if your code specifically needs a 64 bit variable, then naming it as uint_64_t or something similar will always help in associating the size clearly.
In such cases, the code be written as:
#if _64BIT_
typedef long uint_64_t
#else
typedef long long uint_64_t
#endif
But as suggested by Mehrdad, don't use it "just for kicks". : )
Great question.
So what is the point of all this?
It's meant to be for abstraction, but like anything else, it is sometimes misused/overused.
Sometimes it's necessary for backwards compatibility (e.g. typedef VOID void in Windows), sometimes it's necessary for proper abstraction (e.g. typedef unsigned int size_t), and sometimes it's completely pointless logically, but makes typing easier (e.g. typedef char const *LPCSTR in Windows).
When should you decided to use C's built-in standard data types or typedef's data types?
If it makes something easier, or if it implements a proper abstraction barrier, use it.
What exactly that means is something you'll just have to learn over time.
But don't use it "just for kicks"!

What exactly is the FILE keyword in C?

I've started learning some C as a hobby and have blindly used FILE as a declaration for file pointers for quite some time, and I've been wondering. Is this a keyword or special data type for C to handle files with? Does it contain a stream to the file within and other data? Why is it defined as a pointer?
An example to show what I mean to make it a little more clear:
FILE* fp; //<-- this
fp = fopen("datum.txt", "r");
while(!feof(fp)) {
// etc.
}
is this a keyword or special data type for C to handle files with?
What you are refering to is a typedef'd structure used by the standard io library to hold the appropriate data for use of fopen, and its family of functions.
Why is it defined as a pointer?
With a pointer to a struct, you can then pass it as a parameter to a function. This is for example what fgets or fgetc will accept, in the form of function(FILE* fp)
The fopen function will return a pointer to a newly created FILE struct, assigning this new pointer to your unused one will cause them to point to the same thing.
Does it contain a stream to the file within and other data?
The structure definition seems a little more illusive than its description. This is directly taken from my stdio.h, from MinGW32 5.1.4
typedef struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
} FILE;
Which includes the lovely comment before it:
Some believe that nobody in their right mind should make use of the
internals of this structure.
The contents of this structure appear to change greatly on other implementations, the glibc sources usually have some form of commenting but their structure for this is burried under a lot of code.
It would make sense to heed the aforementioned warning and just not worry what it does. :)
FILE is an identifier used as a typedef name, usually for a struct.
The stdio library usually has something like
typedef struct {
...
} FILE;
somewhere. All stdio functions dealing with FILE pointers know the contens of ... and can access the structure members. The C programmers must use functions like fopen, feof, ferror, ungetc etc to create and operate on FILE structures. Such types are called opaque (i.e. you can´t peek inside them but must use accessor functions).
Why is it defined as a pointer?
It isn't. It's a struct to which your code declares a pointer. Note the asterisk in your
FILE* fp;
which is another example of why the asterisk should go with the variable identifier, not the type name:
FILE *fp;
It's not a keyword, it's a data type defined in the ANSI C standard to operate with files. It usually points to an internal structure that describes the file and its current state to the library functions.
It's a special data type. It contains a file handle as well as various flags used internally by the various stdio calls. You'll never need to actually know what's in it, just that it's a data type that you can pass around.
http://www.cplusplus.com/reference/clibrary/cstdio/FILE/
However if you're interested, here's what it looks like:
http://en.allexperts.com/q/C-1587/2008/5/FILE-Structure.htm

Resources