tags:

views:

78

answers:

2

I have a bad feeling that the answer to this question is "no", but I wanted to throw this out there in case anyone has any clever ideas.

I have a set of output routines that take a complex data structure and print it in a textual format. They have prototypes like:

void print_mystruct(struct mystruct *s, FILE *stream)

I wrote it this way so that I can get efficient, buffered output to the terminal, to a file, to the network, etc.

Unfortunately, there's no way that I know of, using standard C99, that I can use these same routines to build up a string in memory.

So my questions are:

  1. is there any clever way that I can efficiently use fputs(), fprintf(), etc. to output to a string?
  2. if not, is there a better paradigm that can efficiently do both buffered file output and string building? The best I can think of is to have my own structure with a vtable (instead of a FILE*). The vtable would have an output function that would either append to a string or call fwrite. But then I'd have to create printf wrappers also.

Any other clever ideas?

A: 

Sure, there's nothing magical about the FILE struct, although I don't know of any built in library function to create one from a string buffer. Here is at least one version of the definition.

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

You could fabricate one of these structs on your own from a string buffer and pass it to your function, and also create a tear-down function that frees the memory.

The question is, which CRT library calls can you use on your version? Obviously anything referring to the file name will fail, since there isn't one. But you could probably use functions like fwrite and fread and fseek, which will be manipulating the pointers and allocating more space if necessary.

Drew Hoskins
Hmm, this approach doesn't sound portable, since the structure is not (AFAIK) standardized. I don't want my solution to be specific to one compiler/runtime.
Josh Haberman
It might be standardized, but I share your intuition. But because your scenario isn't supported, it's unclear that different CRTs would behave in the same way with confronted with your self-made FILE structs.
Drew Hoskins
+1  A: 

There's no portable way of doing this. glibc systems(linux) have open_memstream/fmemopen , other systems might not have something like it.

The portable way is to write to a file and read it back into a string. , or to separate the concerns. Instead of implementing

void print_mystruct(struct mystruct *s,FILE *f);

You'd e.g. implement

char *mystruct_2_str(struct mystruct *s);

Which dynamically allocates a string(Or pass in a buffer), formats it to a string with standard string functions (snprintf etc.) and have the caller decide whether to write that to a FILE*

nos
Thanks for the pointer to open_memstream/fmemopen. Even though these functions aren't portable, it's good to know they exist. Your proposed interface is not ideal, because you waste memory if you're just trying to write the file to a disk. I'm always concerned about how these algorithms will perform when scaled up to very large data sets.
Josh Haberman