所有,
我有一个打印到stream的程序。 我需要在内存中缓冲这个stream,然后根据需要将每一行打印到一个实际的文件中。
由于fprintf()
函数调用必须有一个FILE *
指针,所以我需要在所指向的内存中寻址空间。 我曾经使用过open_memstream()
函数,但在Windows上不支持。
由于malloc()
返回一个void *
指针,可以根据需要奇迹般地转换为必要的指针,我可以使用它作为我的FILE *
指针吗? 如果是的话,那里有什么警告? 我需要注意空间不足吗?
更新:
在findopen_memstream()
的源代码之后,它看起来好像在做一个文件stream到malloc的空间。
既然是这样,而且我已经得到了他们的源代码,那么如果我不能通过mingw得到一个工作版本来交叉编译windows的话。
对于那些追随我的人,有希望! 有一个解决方案。 正如我的问题所述,我正在使用open_memstream()
,这是不支持在Windows上。
由于我有一个File *
指针(这不能改为char *
),我需要重定向到内存,直到以后。 由于我正在处理内存中的文件,所以我查看了mmap()
。 它轻松地解决了这个问题,但是,它只是Linux而已。
但是,windows包含一个名为MapViewOfFile()
mmap()
的推论。 通过#ifdef
的魔法,我已经使用它的任何必要:
#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);
现在我有更多的#ifdef
代码来确定哪些内存映射代码集需要使用。 请注意两个版本之间映射空间的差异。 Windows映射16384 bytes
和Linux映射4096 bytes
。 这是因为我的问题在这里指出,Windows上的较小的值段错误。
#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()
方法被调用。 它用一个空终止的字符结束流,刷新它,然后倒带它。 然后指向内存空间的指针通过一个函数指针,以及适当的流来打印。
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); }
这是可以指向打印的功能之一。 它遍历内存空间并打印每个字符,直到它碰到之前打印的null。
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; }
所有这一切的最终结果是,我有一个流到内存空间就像open_memstream()
,直到还有一个字符指针我可以用来走过内存空间,如果有必要。 它是跨平台的,并且(看起来)功能齐全。
如果有人想要更多的细节或者有关于我应该修复的问题,请添加评论。
号malloc()
只是给你一块(可能未初始化)的内存。 没有什么“神奇”的演员正在进行; 当你做int * buf = malloc(10*sizeof(int);
你正在将buf
指向10个未初始化的int。
FILE对应的东西是FILE * f = malloc(10*sizeof(FILE));
在10个未初始化的FILE结构中指向f
,这没有任何意义。 而且,如果你幸运的话 ,写一个未初始化的文件很可能会导致崩溃。
如果你告诉我们你的目标是什么平台,以及你想达到什么样的目标,那么帮助会更容易。 在POSIX上,可以使用shm_open()
获取指向“共享内存”的fdopen()
,使用fdopen()
将文件描述符变为FILE*
。 是的,它可能会用完空间。
你需要的函数是sprintf()
或相关的snprintf()
,它将把流格式化为一个字符串供以后使用。