简体   繁体   English

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

[英]Can I replace a call to open_memstream with a malloc and an implicit cast?

All, 所有,

I have a program that prints to a stream. 我有一个打印到流的程序。 I need to buffer this stream in memory, and then print each line as necessary to an actual file later. 我需要在内存中缓冲此流,然后根据需要将每行打印到实际文件中。

Since the fprintf() function calls must have a FILE * pointer, I need to have said pointer addressing space in memory. 由于fprintf()函数调用必须有一个FILE *指针,我需要在内存中使用所述指针寻址空间。 I had used the open_memstream() function, but this is not supported on windows. 我曾使用过open_memstream()函数,但Windows不支持此功能。

Since malloc() returns a void * pointer that magically casts to the necessary pointer as needed, could I use that as my FILE * pointer? 由于malloc()返回一个void *指针,它根据需要神奇地转换为必要的指针,我可以将它用作我的FILE *指针吗? If so, what caveats are there? 如果是这样,有什么警告? Do I need to watch out for running out of space? 我需要注意空间不足吗?

Update: 更新:

After finding the source for open_memstream() , which was harder than it should have been, it looks like they are doing a file stream to malloc'd space. 在找到open_memstream()的源代码之后,它看起来比它本来应该更难,看起来它们正在为malloc空间做一个文件流。

Since that is the case, and I've got their source, I'm going to se if I can't get a working version to cross compile for windows with mingw. 既然如此,我已经得到了它们的来源,如果我无法通过mingw获得与Windows交叉编译的工作版本,我将会讨论。

For those who come after me, have hope! 对于那些追随我的人,有希望! There is a solution. 有一个解决方案。 As noted in my question, I was using open_memstream() , which is unsupported on windows. 正如我的问题所述,我使用的是open_memstream() ,它在Windows上不受支持。

Since I have a File * pointer (this cannot be changed to char * ), I needed to redirect it to memory until later. 由于我有一个File *指针(这不能改为char * ),我需要将它重定向到内存直到以后。 Since I'm dealing with a file in memory, I looked into mmap() . 因为我正在处理内存中的文件,所以我查看了mmap() It handily solves the problem, but again, it is linux only. 它轻松地解决了这个问题,但同样,它只是linux。

But, windows includes a corollary to mmap() called MapViewOfFile() . 但是,windows包含一个名为MapViewOfFile() mmap()的推论。 Through the magic of #ifdef I've got it using whichever is necessary: 通过#ifdef的魔力,我可以使用任何必要的东西:

#ifdef WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#endif

Later on, in the main method, I call tmpfile() which is supported on both platforms. 稍后,在main方法中,我调用两个平台都支持的tmpfile() This opens a stream to a guaranteed unique temporary file for me. 这将为我打开一个保证唯一临时文件的流。 Now that I have my FILE * pointer, I need to mmap() the space. 现在我有了我的FILE *指针,我需要mmap()空间。 But mmap() needs a file descriptor, not a stream, so I used the fileno() function to get the new file descriptor. 但是mmap()需要一个文件描述符,而不是一个流,所以我使用了fileno()函数来获取新的文件描述符。

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

Now I have some more #ifdef code to determine which memory mapping codeset needs to be used. 现在我还有一些#ifdef代码来确定需要使用哪个内存映射代码集。 Note the difference in the mapped space between the two versions. 请注意两个版本之间的映射空间的差异。 Windows maps 16384 bytes and linux maps 4096 bytes . Windows映射16384 bytes ,linux映射4096 bytes This is because the smaller value segfaults on windows, as noted in my question here . 这是因为我在这里的问题中提到了窗口上较小的段错误。

#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

A bunch of work now happens, wherin data is sent to the yyout stream. 现在发生了大量工作,将yyout数据发送到yyout流。 Eventually the flushData() method gets called. 最终flushData()方法。 It finalizes the stream with a null terminated character, flushes it, and then rewinds it. 它使用空终止字符最终确定流,刷新它,然后将其倒回。 Then the pointer to the memory space is passed through a function pointer, along with the proper stream to print to. 然后指向内存空间的指针通过一个函数指针,以及要打印到的正确流。

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

This is one of the functions that could be pointed to for printing. 这是可以指向打印的功能之一。 It walks the memory space and prints each char until it hits the null printed earlier. 它遍历内存空间并打印每个char,直到它达到之前打印的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;
}

The end result of all this being that I have a stream to memory space just like open_memstream() , up to also having a char pointer I can use to walk through the memory space if necessary. 所有这一切的最终结果是我有一个流到内存空间就像open_memstream() ,最后还有一个char指针,我可以用来遍历内存空间,如果有必要的话。 It is cross platform, and (seemingly) fully functional. 它是跨平台的,并且(看似)功能齐全。

If anyone wants more details or have notes about problems I should fix, please add a comment. 如果有人想了解更多细节或记录我应该修复的问题,请添加评论。

No. malloc() just gives you a block of (probably uninitialized) memory. 不, malloc()只是给你一块(可能是未初始化的)内存。 There's no "magical" casting going on; 没有“神奇”的铸造正在进行; when you do int * buf = malloc(10*sizeof(int); you are pointing buf at, effectively, 10 uninitialized ints. 当你执行int * buf = malloc(10*sizeof(int);你指向buf ,有效地,10个未初始化的int。

The corresponding thing with a FILE would be FILE * f = malloc(10*sizeof(FILE)); 与FILE相对应的是FILE * f = malloc(10*sizeof(FILE)); which points f at 10 uninitialized FILE structures, which doesn't make any sense. 它指向f在10层初始化文件结构,这没有任何意义。 Furthermore, writing to an uninitialized FILE is likely to result in a crash if you're lucky . 此外,如果您幸运的话 ,写入未初始化的文件可能会导致崩溃。

It's easier to help if you tell us what platforms you're targeting and what you actually want to achieve. 如果您告诉我们您要定位的平台以及您希望实现的目标,则可以更轻松地提供帮助。 On POSIX, you can use shm_open() to get a file descriptor pointing to "shared memory" and fdopen() to turn the file descriptor to a FILE* . 在POSIX上,您可以使用shm_open()来获取指向“共享内存”的fdopen() ,使用fdopen()将文件描述符转换为FILE* Yes, it might run out of space. 是的,它可能会用完空间。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM