Pueden rutinas de salida que imprime en un archivo * pueden utilizar para construir una cadena en C?

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

  •  13-09-2019
  •  | 
  •  

Pregunta

Tengo un mal presentimiento de que la respuesta a esta pregunta es "no", pero quería tirar esto por ahí por si alguien tiene alguna idea inteligente.

Tengo un conjunto de rutinas de salida que tienen una estructura de datos compleja e imprimirlo en un formato textual. Tienen prototipos como:

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

Lo escribí esta manera para que puedo conseguir eficiente, el buffer de salida de la terminal, a un archivo, a la red, etc.

Desafortunadamente, no hay manera de que yo sepa, utilizando el estándar C99, que puedo usar estas mismas rutinas para construir una cadena en la memoria.

Así que mis preguntas son:

  1. ¿hay alguna manera inteligente que pueda utilizar de manera eficiente fputs (), fprintf (), etc. para dar salida a una cadena?
  2. Si no es así, hay una mejor paradigma que puede hacer de manera eficiente tanto en la construcción de salida de archivo y la cadena tamponada? Lo mejor que puedo pensar es tener mi propia estructura con un vtable (en lugar de un archivo *). La viable tendría una función de salida que se agregue a una cadena o llame fwrite. Pero entonces tendría que crear contenedores printf también.

¿Alguna otra idea inteligente?

EDIT: He descubierto que fmemopen() es parte de POSIX.1-2008 (ver: fmemopen () ), pero no se admite ampliamente, al menos de acuerdo con la página de manual libc GNU.

¿Fue útil?

Solución

No hay manera de hacer esto portátil. sistemas glibc (Linux) han open_memstream / fmemopen , otros sistemas no podría tener algo parecido.

La forma portátil es escribir en un archivo y leerlo de nuevo en una cadena. , O para separar las preocupaciones. En lugar de implementar

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

por ejemplo, había aplicar

char *mystruct_2_str(struct mystruct *s);

Lo que asigna dinámicamente una cadena (o pasar en una memoria intermedia), los formatos en una cadena con funciones de cadena estándar (snprintf etc.) y tener la persona que llama decidir si se debe escribir en un archivo que *

Otros consejos

Si no se preocupan por la búsqueda en el archivo, hay una manera portátil (POSIX a todos los objetivos anteriores) para obtener el mismo efecto que fmemopen, pero es bastante costoso. Hacer una tubería y un nuevo hilo individual, y fdopen el extremo de escritura de la tubería en el subproceso de llamada. El nuevo hilo lee entonces desde el extremo de lectura de la tubería y pone los datos en el búfer de cadena. Tener el nuevo hilo de retorno cuando se pone EOF de la tubería; ya que está separado, no hay que hacer la limpieza.

Por supuesto, no hay nada mágico sobre la estructura FILE, aunque no conozco ningún construida en función de biblioteca para crear uno de un búfer de cadena. Aquí es al menos una versión de la definición.

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

Se puede fabricar una de estas estructuras en su propio desde un búfer de cadena y pasarlo a su función, y también crear una función de desmontaje que libera la memoria.

La pregunta es, que las llamadas biblioteca CRT se puede utilizar en su versión más reciente? Obviamente nada que se refiera al nombre del archivo fallará, ya que no es uno. Pero probablemente podría utilizar funciones como fwrite y fread y fseek, que será la manipulación de los punteros y asignación de más espacio si es necesario.

#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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top