I want to do something that seems impossible.
I want to write 3 files: main.c, foo.h, foo.c.
The idea is to define a struct in foo.h or foo.c in such a way that its members are visible in main.c. One of the struct members have type FILE
as defined in the standard header <stdio.h>
. But the functions and macros of <stdio.h>
have to keep not visible inside the file main.c.
The solution would have to be compliant with standard C (C99 and/or C11) and portable. Is that possible?
The header foo.h is #included in both, main.c and foo.c.
The standard header <stdio.h>
is #included only in foo.c, but not in main.c.
I want to declare a struct
as follows:
struct myfile_s {
FILE *F;
char *filename;
char buff[100];
} myfile;
For what follows, only the member FILE *F
is important.
The struct myfile
will be initialized and modified by functions appearing in foo.c.
The intent is to do file operations on myfile
through extern
functions declared in foo.h, which in turn has to be defined in foo.c.
The file operations involve standard functions of <stdio.h>
, but these functions have to be hidden in the file main.c.
However, I want to directly access, from main.c, to the members of myfile
.
This would imply that the definition of struct myfile_s
has to be done in foo.h (that is, it cannot be "delayed" with the trick of using incomplete struct declarations, like struct myfile_s ;
).
In short, I would want that the type FILE
be visible in main.c and/or foo.h, but the rest of <stdio.h>
declarations keep hidden for them.
Another restriction: the idea of directly copying "at hand" the definition of FILE
provided by <stdio.h>
would not be desirable, because the code would have to be portable.
My first try was hidding the struct myfile
by writting it inside of foo.c.
The code was:
foo.h
struct myfile_s;
struct myfile_s myfile;
extern void startfile(struct myfile *f);
foo.c
#include <stdio.h>
#include "foo.h"
struct myfile_s {
FILE *F;
char *filename;
char buff[100];
} myfile;
void startfile(struct myfile *f)
{
// Do some stuff...
}
main.c
#include "foo.h"
int main(void)
{
myfile.F = NULL; // This kind of access bring error, but I want to do it anyway!!
startfile(&myfile);
return 0;
}
The delayed struct myfile_s
declaration avoids the need to include <stdio.h>
in foo.h, so the header works fine, but the struct type remains incomplete, so the access to myfile.F
cannot be done in main.c.
So: How can I access to myfile.F?
I tried another way that, of course, gives error too:
foo.h
struct myfile_s {
FILE *F;
char *filename;
char buff[100];
} myfile;
extern void startfile(struct myfile *f);
foo.c
#include <stdio.h>
#include "foo.h"
void startfile(struct myfile *f)
{
// Do some stuff...
}
struct myfile_s {
void *pPrivateThings; // This could be the FILE* or another private structure
char *filename;
char buff[100];
} myfile;
I would allocate another private structure on creation:
struct myprivatefile_s {
FILE *F;
// You could add other fields here that are not public
} myprivatefile;
myprivatefile *privateThings = malloc(sizeof(myprivatefile));
myfile.pPrivateThings = privateThings;
privateThings->F = fopen();
That way you can keep on adding things that aren't required to be visible (i.e. private) to your heart's content.
That's all needlessly complicated, isn't it?
It looks as if you don't really know what you want. Why do you want to have a single instance of myfile
in foo.h
? Why do you want to set myfile.F
explicitly in main
? Why not write a function like myfile_init
for that in foo.c
, which has full access?
I'd do a typedef of an opaque struct in foo.h
, define the stuff and implement constructor and accessor functions in foo.h
and then create an instance of myfile
in main.c
:
foo.h
typedef struct Myfile Myfile;
Myfile *myfile_open(const char *filename);
myfile_process(Myfile *f, ...);
int myfile_close(Myfile *f);
foo.c
#include <stdio.h>
struct Myfile {
FILE *f;
...
};
// implement myfile_xxx functions
main.c
#include "foo.h"
int main()
{
Myfile *f = myfile_open("rhubarb.txt");
if (f == NULL) exit(1);
myfile_process(f, ...);
myfile_close(f);
return 0;
}
No need to partially include other headers. By moving initialisation to myfile_open
, everything is neatly encapsulated in foo.c
. The main program sees only handles. Quite like the standard FILE *
handles, really.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With