将函数转换为从字符串读取而不是 C 中的文件

发布于 2024-08-25 05:24:52 字数 874 浏览 3 评论 0原文

我的任务是更新一个函数,该函数当前从磁盘读取配置文件并填充一个结构:

static int LoadFromFile(FILE *Stream, ConfigStructure *cs)
{
  int tempInt;

   ...

  if ( fscanf( Stream, "Version: %d\n",&tempInt) != 1 )
  {
    printf("Unable to read version number\n");
    return 0;
  }
  cs->Version = tempInt;
   ...

}

相当于:

static int LoadFromString(char *Stream, ConfigStructure *cs)

到一个允许我们绕过将配置写入磁盘并直接将其传递到内存中的函数,大致 需要注意的是:

  • 当前的 LoadFromFile 函数非常密集和复杂,以向后兼容的方式读取数十个版本的配置文件,这使得整体逻辑的重复变得相当痛苦。
  • 生成配置文件的函数和读取配置文件的函数源自旧系统的完全不同部分,因此不共享任何数据结构,因此我无法直接传递这些函数。我可能会编写一个包装器,但同样,它需要处理以向后兼容的方式传入的任何结构。
  • 我很想将文件按原样作为字符串传递(如上面的原型所示),并将所有 fscanf 转换为 sscanf,但随后我必须手动处理指针的增量(并可能处理缓冲区溢出错误)。
  • 这必须保留在 C 中,因此没有像流这样的 C++ 功能可以在这里提供帮助,

我是否缺少更好的选择?有没有办法创建一个 FILE * 实际上只指向内存中的位置而不是磁盘上的位置?非常感谢任何指示、建议或其他帮助。

I've been tasked with updating a function which currently reads in a configuration file from disk and populates a structure:

static int LoadFromFile(FILE *Stream, ConfigStructure *cs)
{
  int tempInt;

   ...

  if ( fscanf( Stream, "Version: %d\n",&tempInt) != 1 )
  {
    printf("Unable to read version number\n");
    return 0;
  }
  cs->Version = tempInt;
   ...

}

to one which allows us to bypass writing the configuration to disk and instead pass it directly in memory, roughly equivalent to this:

static int LoadFromString(char *Stream, ConfigStructure *cs)

A few things to note:

  • The current LoadFromFile function is incredibly dense and complex, reading dozens of versions of the config file in a backward compatible manner, which makes duplication of the overall logic quite a pain.
  • The functions that generate the config file and those that read it originate in totally different parts of the old system and therefore don't share any data structures so I can't pass those directly. I could potentially write a wrapper, but again, it would need to handle any structure passed in in a backwards compatible manner.
  • I'm tempted to just pass the file as is in as a string (as in the prototype above) and convert all the fscanf's to sscanf's but then I have to handle incrementing the pointer along (and potentially dealing with buffer overrun errors) manually.
  • This has to remain in C, so no C++ functionality like streams can help here

Am I missing a better option? Is there some way to create a FILE * that actually just points to a location in memory instead of on disk? Any pointers, suggestions or other help is greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ま柒月 2024-09-01 05:24:52

如果您无法传递结构并且必须将数据作为字符串传递,那么您应该能够调整函数以从字符串而不是文件中读取。如果函数像您描述的那样复杂,那么转换 fscanf->sscanf 可能是最直接的方法。

这是使用上面的函数原型的一个想法。读入整个数据字符串(不对其进行任何处理)并将其存储在本地缓冲区中。这样,代码就可以像使用文件一样随机访问数据,并使缓冲区溢出更容易预测和避免。首先malloc分配一个合理大小的缓冲区,将数据复制到其中,然后根据需要为自己realloc更多空间。一旦您拥有整个数据缓冲区的本地副本,请扫描它并提取您需要的任何数据。

请注意,如果 '\0' 字符是有效输入,这可能会变得棘手。在这种情况下,您必须添加额外的逻辑来测试这是输入字符串的结尾还是只是零字节(难度取决于数据缓冲区的特定格式)。

If you can't pass structures and must pass the data as a string, then you should be able to tweak your function to read from a string instead of a file. If the function is as complicated as you describe, then converting fscanf->sscanf would possibly be the most straightforward way to go.

Here's an idea using your function prototype above. Read in the entire data string (without processing any of it) and store it in a local buffer. That way the code can have random access to the data as it can with a file and making buffer overruns easier to predict and avoid. Start by mallocing a reasonably-sized buffer, copy data into it, and realloc yourself more space as needed. Once you have a local copy of the entire data buffer, scan through it and extract whatever data you need.

Note that this might get tricky if '\0' characters are valid input. In that case, you would have to add additional logic to test if this was the end of the input string or just a zero byte (difficulty depending on the particular format of your data buffer).

深海夜未眠 2024-09-01 05:24:52

由于您试图将文件数据保留在内存中,因此您应该能够使用共享内存< /a>。 POSIX 共享内存实际上是映射内存的一种变体。共享内存对象可以使用 mmap( )如果有必要的话。共享内存通常用作 IPC 机制,但您应该能够根据您的情况使用它。

以下示例代码使用 POSIX 共享内存 (shm_open() & shm_unlink()< /strong>) 与 FILE * 结合使用,将文本写入共享内存对象,然后将其读回。

#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>

#define MAX_LEN 1024

int main(int argc, char ** argv)
{
    int    fd;
    FILE * fp;
    char * buf[MAX_LEN];

    fd = shm_open("/test", O_CREAT | O_RDWR, 0600);

    ftruncate(fd, MAX_LEN);

    fp = fdopen(fd, "r+");

    fprintf(fp, "Hello_World!\n");

    rewind(fp);

    fscanf(fp, "%s", buf);

    fprintf(stdout, "%s\n", buf);

    fclose(fp);

    shm_unlink("/test");

    return 0;
}

注意:在 Linux 上使用 gcc 编译此示例时,我必须将 -lrt 传递给链接器。

Since you are trying to keep the file data in memory, you should be able to use shared memory. POSIX shared memory is actually a variation of mapped memory. The shared memory object can be mapped into the process address space using mmap() if necessary. Shared memory is usually used as an IPC mechanism, but you should be able to use it for your situation.

The following example code uses POSIX shared memory (shm_open() & shm_unlink()) in conjunction with a FILE * to write text to the shared memory object and then read it back.

#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>

#define MAX_LEN 1024

int main(int argc, char ** argv)
{
    int    fd;
    FILE * fp;
    char * buf[MAX_LEN];

    fd = shm_open("/test", O_CREAT | O_RDWR, 0600);

    ftruncate(fd, MAX_LEN);

    fp = fdopen(fd, "r+");

    fprintf(fp, "Hello_World!\n");

    rewind(fp);

    fscanf(fp, "%s", buf);

    fprintf(stdout, "%s\n", buf);

    fclose(fp);

    shm_unlink("/test");

    return 0;
}

Note: I had to pass -lrt to the linker when compiling this example with gcc on Linux.

记忆で 2024-09-01 05:24:52
  • 使用mkstemp()创建一个临时文件。它采用 char * 作为参数,并将其用作文件名的模板。但是,它将返回一个文件描述符。

  • 使用tmpfile() 。它返回 FILE *,但有一些 安全问题而且,您必须自己复制字符串。

  • 使用mmap() Beej 指南寻求帮助)

  • Use mkstemp() to create a temporary file. It takes char * as argument and uses it as a template for the file's name. But, it will return a file descriptor.

  • Use tmpfile(). It returns FILE *, but has some security issues and also, you have to copy the string yourself.

  • Use mmap() ( Beej's Guide for help)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文