3

我有一种不好的感觉,这个问题的答案是“不”,但我想把它扔在那里,以防有人有任何聪明的想法。

我有一组输出例程,它们采用复杂的数据结构并以文本格式打印它。他们的原型如下:

void print_mystruct(struct mystruct *s, FILE *stream)

我这样写是为了获得高效的缓冲输出到终端、文件、网络等。

不幸的是,据我所知,使用标准 C99,我无法使用这些相同的例程在内存中构建字符串。

所以我的问题是:

  1. 有什么聪明的方法可以有效地使用 fputs()、fprintf() 等输出到字符串?
  2. 如果没有,是否有更好的范例可以有效地进行缓冲文件输出和字符串构建?我能想到的最好的方法是使用 vtable(而不是 FILE*)拥有自己的结构。vtable 将有一个输出函数,可以附加到字符串或调用 fwrite。但是我还必须创建 printf 包装器。

还有其他聪明的想法吗?

编辑:我发现它fmemopen()是 POSIX.1-2008 的一部分(参见:fmemopen())但没有得到广泛支持,至少根据 GNU libc 手册页。

4

4 回答 4

1

没有便携的方法可以做到这一点。glibc 系统(linux)有open_memstream/fmemopen,其他系统可能没有类似的东西。

可移植的方法是写入文件并将其读回字符串。,或分离关注点。而不是实施

void print_mystruct(struct mystruct *s,FILE *f);

你会例如实施

char *mystruct_2_str(struct mystruct *s);

它动态分配字符串(或传入缓冲区),使用标准字符串函数(snprintf 等)将其格式化为字符串,并让调用者决定是否将其写入 FILE*

于 2009-08-13T06:18:28.833 回答
1

如果您不关心在 FILE 上查找,则有一种可移植的(适用于所有早期 POSIX 目标)的方法来获得与 相同的效果fmemopen,但它的成本相当高。制作一个管道和一个新的分离线程,并fdopen在调用线程中写入管道。然后新线程从管道的读取端读取数据并将数据放入字符串缓冲区。当新线程从管道获取 EOF 时返回;因为它是分离的,所以没有清理工作要做。

于 2011-09-04T19:33:00.780 回答
0

当然,FILE 结构没有什么神奇之处,尽管我不知道有任何内置库函数可以从字符串缓冲区创建一个。这是定义的至少一个版本。

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;

您可以从字符串缓冲区中自己制作其中一个结构并将其传递给您的函数,还可以创建一个释放内存的拆卸函数。

问题是,您可以在您的版本上使用哪些 CRT 库调用?显然,任何引用文件名的内容都会失败,因为没有文件名。但是您可能可以使用 fwrite、fread 和 fseek 之类的函数,它们将操纵指针并在必要时分配更多空间。

于 2009-08-13T06:04:38.003 回答
0
#include <stdio.h>
#include <stdlib.h>

char* file_to_string(FILE *f, int *len) {
  if (fseek(f, 0, SEEK_END)) handle_error();
  int buflen = ftell(f);
  if (len) *len = buflen;
  char *buf = malloc(buflen + 1);
  buf[buflen] = '\0';
  rewind(f);
  size_t readlen = fread(buf, 1, buflen, f);
  if (readlen != buflen) handle_error();
  // in particular, note readlen might not equal buflen in the face of text-mode
  // conversions, but tmpfile() indicates binary-mode, so doesn't affect this
  // case
  return buf;
}

int main() {
  FILE *temp = tmpfile();

  // use FILE interface
  fputs("written to temporary file\n", temp);

  char *s = file_to_string(temp, NULL);
  // now you have contents as a string
  free(s);

  // can also rewind the FILE and process it incrementally, etc.

  return 0;
}
于 2011-01-03T07:02:04.560 回答