C中的字符串流
Posted
技术标签:
【中文标题】C中的字符串流【英文标题】:String Stream in C 【发布时间】:2011-03-29 17:05:09 【问题描述】:print2fp(const void *buffer, size_t size, FILE *stream)
if(fwrite(buffer, 1, size, stream) != size)
return -1;
return 0;
如何将数据写入字符串流而不是文件流?
【问题讨论】:
字符串流 gnu.org/s/libc/manual/html_node/String-Streams.html 与我之前的问题类似:***.com/questions/1741191/… 由于您没有 POSIX 2008 字符串流函数,您可能不走运 - 除非您能找到一个可以很好地模拟它们以满足您的目的的库。 【参考方案1】:使用sprintf
:http://www.cplusplus.com/reference/cstdio/sprintf/
这是参考中的一个示例:
#include <stdio.h>
int main ()
char buffer [50];
int n, a=5, b=3;
n = sprintf(buffer, "%d plus %d is %d", a, b, a+b);
printf("[%s] is a string %d chars long\n", buffer, n);
return 0;
输出:
[5 plus 3 is 8] is a string 13 chars long
根据 cmets 中的建议进行更新:
使用snprintf
,因为它更安全(它可以防止缓冲区溢出攻击)并且更便携。
#include <stdio.h>
int main ()
int sizeOfBuffer = 50;
char buffer[sizeOfBuffer];
int n, a = 5, b = 3;
n = snprintf(buffer, sizeOfBuffer, "%d plus %d is %d", a, b, a+b);
printf ("[%s] is a string %d chars long\n", buffer, n);
return 0;
请注意,snprintf
的第二个参数实际上是允许使用的最大大小,因此您可以将其设置为低于sizeOfBuffer
的值,但是对于您的情况,这是不必要的。 snprintf
只写入 sizeOfBuffer-1
字符并使用最后一个字节作为终止字符。
这是snprintf
文档的链接:http://www.cplusplus.com/reference/cstdio/snprintf/
【讨论】:
不要使用 sprintf(),几乎任何 sprintf() 的使用都会在一段时间内爆炸。请改用 asprintf(),它会为您分配所需长度的缓冲区。 或snprintf
在可移植代码中。另外,请不要链接到 cplusplus.com,该网站充满了错误。 cppreference.com 更好。
另外,sprintf 和 vsprintf 也有安全问题。 codecogs.com/library/computing/c/stdio.h/… " sprintf 和 vsprintf 函数很容易被滥用,从而使恶意用户能够通过缓冲区溢出攻击任意更改正在运行的程序的功能。由于 sprintf 和 vsprintf 假定一个无限长的字符串,调用者必须小心不要溢出实际空间;这通常很难保证。为了安全,程序员应该使用 snprintf 接口。"
两年前我没有对 larsmans 的评论做出反应,这太糟糕了,但感谢迈克,我现在看到了他们。感谢您指出 sprintf 的缺陷。教人礼貌当然是一种美德。 cplusplus.com 与 cpprefference 的用法:可能是 cplusplus 有一些错误,可能是由于在几个地方的示例可能提供了特定参考的好示例,但使用了有问题的函数(如 sprintf)沿示例。我个人觉得 cplusplus.com 更容易阅读,在某些应用程序中,理解比正确更重要。
一些编译器会期望行前有一个 const : int sizeOfBuffer = 50;【参考方案2】:
posix 2008 标准中有一个非常简洁的函数:open_memstream()。你可以这样使用它:
char* buffer = NULL;
size_t bufferSize = 0;
FILE* myStream = open_memstream(&buffer, &bufferSize);
fprintf(myStream, "You can output anything to myStream, just as you can with stdout.\n");
myComplexPrintFunction(myStream); //Append something of completely unknown size.
fclose(myStream); //This will set buffer and bufferSize.
printf("I can do anything with the resulting string now. It is: \"%s\"\n", buffer);
free(buffer);
【讨论】:
open_memstream
有什么好的替代品吗?许多平台(其中包括 solaris)[尚未] 提供此功能。
@BrianVandenberg 最接近的是asprintf()
,并非所有平台都提供。所有其他替代方案要么存在严重的安全问题,因为它们可能会超出提供的缓冲区(sprintf()
和 fmemopen()
),要么强制您运行两次字符串生成以避免在您的预分配缓冲区太小时(snprintf()
)时失败。只有 asprintf()
和 open_memstream()
提供安全的单通道语义。但是,如果asprintf()
适合您,您可以通过两次vsprintf()
轻松实现您自己的版本。
感谢您的回复。我正在将一个我不是维护者的库移植到使用 open_memstream
的 Solaris 上,我希望找到一种方法来提供自定义版本以避免更改其代码。我可能不得不使用带有自定义 write()/close()
的库插入(当然是调用 libc 版本)。
@cmaster @BrianVandenberg 关于fmemopen
,它不会溢出缓冲区。这在手册页 (Attempts to write more than size bytes ... result in an error
) 和 Open Group 规范 (This interface prevents overflow.
) 中有明确说明。有一个错误,已于 2015 年 6 月修复。
@Fuujuhi 啊,感谢您指出这一点。这将fmemopen()
与snprintf()
归为同一类:溢出安全,但在缓冲区空间不足的情况下未终止的部分输出。看起来您绝对必须检查来自写作调用 和 fclose()
调用的所有错误代码,才能安全地识别这种情况。以上是关于C中的字符串流的主要内容,如果未能解决你的问题,请参考以下文章