Possono routine di output che stampare su un file * essere utilizzati per costruire una stringa in C?

StackOverflow https://stackoverflow.com/questions/1270212

  •  13-09-2019
  •  | 
  •  

Domanda

Ho una brutta sensazione che la risposta a questa domanda è "no", ma volevo buttare questo là fuori nel caso in cui qualcuno ha qualche idea intelligente.

Ho una serie di routine di output che prendono una struttura dati complessa e stamparlo in formato testuale. Hanno prototipi come:

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

ho scritto in questo modo in modo che posso ottenere efficiente, uscita tamponata al terminale, in un file, alla rete, ecc.

Purtroppo, non c'è modo che io sappia, utilizzando standard di C99, che posso usare queste stesse routine per costruire una stringa nella memoria.

Quindi le mie domande sono le seguenti:

  1. esiste un modo intelligente che posso utilizzare in modo efficiente fputs (), fprintf (), ecc per l'uscita in una stringa?
  2. se non, c'è un paradigma meglio che può fare entrambe le cose in modo efficiente costruzione file di output e la stringa tamponata? Il meglio che posso pensare è quello di avere la mia propria struttura con una vtable (invece di un file *). Vtable avrebbe una funzione di uscita che sia aggiungere a una stringa o chiamare fwrite. Ma poi avrei dovuto creare involucri printf anche.

Tutte le altre idee intelligenti?

EDIT: ho scoperto che fmemopen() fa parte di POSIX.1-2008 (vedi: fmemopen () ), ma non è ampiamente supportato, almeno secondo libc manpage GNU.

È stato utile?

Soluzione

Non c'è modo di fare questo portatile. sistemi di glibc (Linux) hanno open_memstream / fmemopen , gli altri sistemi non potrebbero avere qualcosa di simile.

Il modo portatile è di scrivere su un file e leggere di nuovo in una stringa. , O per separare le preoccupazioni. Invece di attuazione

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

Faresti esempio implementare

char *mystruct_2_str(struct mystruct *s);

Il che alloca dinamicamente una stringa (o si passa in un buffer), formati in una stringa con le funzioni di stringa standard (snprintf ecc) e hanno il chiamante decidere di scrivere che in un file *

Altri suggerimenti

Se non si preoccupano che cercano sul file, c'è un portatile (a tutti i target POSIX precedenti) modo per ottenere lo stesso effetto di fmemopen, ma è piuttosto costoso. Fare un tubo e un nuovo thread distaccato, e fdopen la fine scrittura del tubo nel thread chiamante. Il nuovo thread legge poi dalla fine lettura del tubo e inserisce i dati nel buffer di stringa. Avere il nuovo ritorno del filo quando si arriva EOF dal tubo; dal momento che è indipendente, non c'è pulizia da fare.

Certo, non c'è nulla di magico struct FILE, anche se non conosco nessun costruito in funzione di libreria per creare uno da un buffer di stringa. Ecco almeno una versione della definizione.

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

Si potrebbe realizzare uno di questi le strutture da soli da un buffer di stringa e passarlo alla funzione, e creare anche una funzione di strappo verso il basso che libera la memoria.

La domanda è, che le chiamate libreria CRT è possibile utilizzare sul vostra versione? Ovviamente nulla riferimento al nome del file avrà esito negativo, dal momento che non ce n'è uno. Ma probabilmente si potrebbe utilizzare funzioni come fwrite e fread e fseek, che saranno manipolando i puntatori e assegnazione di più spazio, se necessario.

#include <stdio.h>
#include <stdlib.h>

char* file_to_string(FILE *f, int *len) {
  if (fseek(f, 0, SEEK_END)) handle_error();
  int buflen = ftell(f);
  if (len) *len = buflen;
  char *buf = malloc(buflen + 1);
  buf[buflen] = '\0';
  rewind(f);
  size_t readlen = fread(buf, 1, buflen, f);
  if (readlen != buflen) handle_error();
  // in particular, note readlen might not equal buflen in the face of text-mode
  // conversions, but tmpfile() indicates binary-mode, so doesn't affect this
  // case
  return buf;
}

int main() {
  FILE *temp = tmpfile();

  // use FILE interface
  fputs("written to temporary file\n", temp);

  char *s = file_to_string(temp, NULL);
  // now you have contents as a string
  free(s);

  // can also rewind the FILE and process it incrementally, etc.

  return 0;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top