Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to hide a portion of a standard header (in C)?

Tags:

c

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...
}
like image 443
pablo1977 Avatar asked Jan 21 '14 09:01

pablo1977


2 Answers

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.

like image 155
noelicus Avatar answered Oct 31 '22 23:10

noelicus


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.

like image 32
M Oehm Avatar answered Oct 31 '22 23:10

M Oehm