¿Puedo reemplazar una llamada a open_memstream con un malloc y una conversión implícita?

Todos,

Tengo un progtwig que se imprime en una secuencia. Necesito almacenar este flujo en la memoria y luego imprimir cada línea según sea necesario para un archivo real más tarde.

Como las llamadas a la función fprintf() deben tener un puntero FILE * , necesito tener dicho espacio de direccionamiento de punteros en la memoria. Había usado la función open_memstream() , pero esto no es compatible con Windows.

Ya que malloc() devuelve un puntero void * que se lanza mágicamente al puntero necesario según sea necesario, ¿podría usar eso como mi puntero FILE * ? Si es así, ¿qué advertencias hay? ¿Debo tener cuidado de no quedarme sin espacio?

Actualizar:

Después de encontrar la fuente para open_memstream() , que fue más difícil de lo que debería haber sido, parece que están haciendo un flujo de archivos al espacio malloc’d.

Dado que ese es el caso, y tengo su fuente, voy a ver si no puedo conseguir una versión funcional para comstackr de forma cruzada para windows con mingw.

¡Para los que vienen después de mí, tengan esperanza! Hay una solucion. Como se señaló en mi pregunta, estaba usando open_memstream() , que no es compatible con Windows.

Como tengo un puntero a File * (esto no se puede cambiar a char * ), tuve que redirigirlo a la memoria hasta más tarde. Ya que estoy tratando con un archivo en la memoria, busqué en mmap() . Resuelve fácilmente el problema, pero nuevamente, es solo Linux.

Pero, las ventanas incluyen un corolario a mmap() llamado MapViewOfFile() . A través de la magia de #ifdef lo tengo usando lo que sea necesario:

 #ifdef WIN32 #include  #else #include  #endif 

Más adelante, en el método principal, llamo a tmpfile() que es compatible con ambas plataformas. Esto abre un flujo a un archivo temporal único garantizado para mí. Ahora que tengo mi puntero FILE * , necesito mmap() el espacio. Pero mmap() necesita un descriptor de archivo, no una secuencia, así que usé la función fileno() para obtener el nuevo descriptor de archivo.

 /* create tmp file and get file descriptor */ int fd; yyout = tmpfile(); fd = fileno(yyout); 

Ahora tengo más código #ifdef para determinar qué #ifdef códigos de asignación de memoria se debe usar. Note la diferencia en el espacio mapeado entre las dos versiones. Windows mapea 16384 bytes y linux mapea 4096 bytes . Esto se debe a que el valor más pequeño segrega en las ventanas, como se indica en mi pregunta aquí .

 #ifdef WIN32 HANDLE fm; HANDLE h = (HANDLE) _get_osfhandle (fd); fm = CreateFileMapping( h, NULL, PAGE_READWRITE|SEC_RESERVE, 0, 16384, NULL); if (fm == NULL) { fprintf (stderr, "%s: Couldn't access memory space! %s\n", argv[0], strerror (GetLastError())); exit(GetLastError()); } bp = (char*)MapViewOfFile( fm, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (bp == NULL) { fprintf (stderr, "%s: Couldn't fill memory space! %s\n", argv[0], strerror (GetLastError())); exit(GetLastError()); } #else bp = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0); if (bp == MAP_FAILED) { fprintf (stderr, "%s: Couldn't access memory space! %s\n", argv[0], FileName, strerror (errno)); exit(errno); } #endif 

Ahora se realiza un montón de trabajo, donde los datos se envían a la secuencia de yyout . Finalmente, se llama al método flushData() . Finaliza el flujo con un carácter terminado en nulo, lo vacía y luego lo rebobina. Luego, el puntero al espacio de memoria pasa a través de un puntero de función, junto con el flujo adecuado para imprimir.

 void flushData(void) { /* write out data in the stream and reset */ while (currFields < headerFields) { fprintf(yyout, ",\"\""); currFields++; } currFields = 0; fprintf(yyout, "%c%c%c", 13, 10, '\0'); fflush(yyout); rewind(yyout); if (faqLine == 1) { faqLine = 0; /* don't print faq's to the data file */ } else { (*printString)(outfile, bp); fflush(outfile); } fflush(yyout); rewind(yyout); } 

Esta es una de las funciones a las que se puede apuntar para imprimir. Recorre el espacio de la memoria e imprime cada carácter hasta que alcanza el nulo impreso anteriormente.

 int printAnsi( FILE *outstream, char *string) { /* loop over the chars in string and print them to the outputstream as ansi */ char * ps = string; while (*ps != '\0') { fprintf(outstream, "%c", *ps); ps++; } return 0; } 

El resultado final de todo esto es que tengo un flujo al espacio de memoria como open_memstream() , hasta tener también un puntero de caracteres que puedo usar para recorrer el espacio de memoria si es necesario. Es multiplataforma y (aparentemente) completamente funcional.

Si alguien desea más detalles o tiene notas sobre los problemas que debo solucionar, agregue un comentario.

No. malloc() solo te da un bloque de memoria (probablemente sin inicializar). No hay ningún casting “mágico” en marcha; cuando lo hace int * buf = malloc(10*sizeof(int); está apuntando buf a, efectivamente, 10 ints sin inicializar.

La cosa correspondiente con un ARCHIVO sería el FILE * f = malloc(10*sizeof(FILE)); que apunta a 10 estructuras de ARCHIVO no inicializadas, lo que no tiene ningún sentido. Además, escribir en un ARCHIVO sin inicializar puede provocar una caída si tienes suerte .

Es más fácil ayudar si nos dice qué plataformas está apuntando y qué quiere lograr realmente. En POSIX, puede usar shm_open() para obtener un descriptor de archivo que apunta a “memoria compartida” y fdopen() para convertir el descriptor de archivo en un FILE* . Sí, podría quedarse sin espacio.

La función que desea es sprintf() o la snprintf() relacionada, que formateará una secuencia a una cadena para su uso posterior.