我可以用malloc和隐式转换替换对open_memstream的调用吗?

时间:2012-04-24 19:54:57

标签: c windows stream malloc

所有

我有一个打印到流的程序。我需要在内存中缓冲此流,然后根据需要将每行打印到实际文件中。

由于fprintf()函数调用必须有FILE *指针,我需要在内存中使用指针寻址空间。我使用过open_memstream()函数,但Windows不支持。

由于malloc()返回一个void *指针,根据需要神奇地转换为必要的指针,我可以将其用作FILE *指针吗?如果是这样,有什么警告?我需要注意空间不足吗?

更新

找到open_memstream()的源代码后,它本来就比它应该更难,看起来它们正在为malloc空间做一个文件流。

既然如此,而且我已经得到了它们的来源,那么如果我无法通过mingw获得一个工作版本来交叉编译,那么我将会这样做。

3 个答案:

答案 0 :(得分:6)

对于那些追随我的人,有希望!有一个解决方案。正如我的问题所述,我使用的是open_memstream(),这在Windows上不受支持。

由于我有File *指针(不能更改为char *),我需要将其重定向到内存,直到稍后。由于我正在处理内存中的文件,因此我查看了mmap()。它轻松地解决了这个问题,但同样,它只是linux。

但是,Windows包含名为mmap()的{​​{1}}的推论。通过MapViewOfFile()的魔力,我可以使用任何必要的东西:

#ifdef

稍后,在main方法中,我调用两个平台都支持的#ifdef WIN32 #include <windows.h> #else #include <sys/mman.h> #endif 。这将为我打开一个保证唯一临时文件的流。既然我有tmpfile()指针,我需要FILE *空间。但是mmap()需要文件描述符,而不是流,所以我使用mmap()函数来获取新的文件描述符。

fileno()

现在我还有一些/* create tmp file and get file descriptor */ int fd; yyout = tmpfile(); fd = fileno(yyout); 代码来确定需要使用哪个内存映射代码集。请注意两个版本之间的映射空间的差异。 Windows映射#ifdef和linux映射16384 bytes。这是因为my question here中提到的窗口上的值较小的段错误。

4096 bytes

现在发生了大量工作,将数据发送到#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 流。最终调用yyout方法。它使用空终止字符最终确定流,刷新它,然后将其倒回。然后指向内存空间的指针通过一个函数指针,以及要打印到的正确流。

flushData()

这是可以指向打印的功能之一。它遍历内存空间并打印每个char,直到它达到之前打印的null。

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);
}

所有这一切的最终结果是我有一个像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; } 一样的内存空间流,直到还有一个char指针我可以用来在必要时遍历内存空间。它是跨平台的,并且(看似)功能齐全。

如果有人想了解更多细节或记录我应该修复的问题,请添加评论。

答案 1 :(得分:0)

没有。 malloc()只是给你一块(可能是未初始化的)内存。没有“神奇”的铸造正在进行;当您执行int * buf = malloc(10*sizeof(int);时,您有效地将buf指向10个未初始化的整数。

与FILE相对应的是FILE * f = malloc(10*sizeof(FILE));,它将f指向10个未初始化的FILE结构,这没有任何意义。此外,如果您幸运,写入未初始化的FILE可能会导致崩溃。

如果您告诉我们您要定位的平台以及您实际想要实现的目标,那么您可以更轻松地提供帮助。在POSIX上,您可以使用shm_open()来获取指向“共享内存”的文件描述符,并使用fdopen()将文件描述符转换为FILE*。是的,它可能用完了空间。

答案 2 :(得分:0)

您想要的功能是sprintf()或相关的snprintf(),它会将流格式化为字符串供以后使用。