为什么使用asprintf()而不是sprintf()?

Bra*_*ing 48 c printf gnu asprintf

我很难理解你为什么需要asprintf.它在手册中说

的功能asprintf()vasprintf()是的类似物sprintf(3)vsprintf(3),除了它们分配一个字符串足够大以容纳包括终止空字节的输出,并且经由第一个参数的指针返回到它.应该传递此指针 free(3)以在不再需要时释放已分配的存储.

所以这是我试图理解的例子:

asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));
Run Code Online (Sandbox Code Playgroud)

如果缓冲区分配足够大的字符串而不是说char*=(字符串),那有什么区别

sli*_*lim 110

如果使用sprintf()or vsprintf(),则需要先分配缓冲区,并且需要确保缓冲区足够大以包含sprintf写入的内容.否则sprintf()将愉快地覆盖缓冲区末尾之外的任何内存.

char* x = malloc(5 * sizeof(char));
// writes "123456" +null but overruns the buffer
sprintf(x,"%s%s%s", "12", "34", "56");
Run Code Online (Sandbox Code Playgroud)

...写入'6'并终止null超出分配给的空间的末尾x,要么破坏其他变量,要么导致分段错误.

如果你很幸运,它会在分配的块之间记录内存,并且不会造成任何伤害 - 这一次.这会导致间歇性的错误 - 最难诊断的错误.使用像ElectricFence这样的工具会导致超速失败,这很好.

提供过长输入的非恶意用户可能会导致程序以意外方式运行.恶意用户可以利用它作为将自己的可执行代码引入系统的方法.

防止这种情况的一个防范是使用snprintf(),它将字符串截断为您提供的最大长度.

char *x = malloc(5 * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null
Run Code Online (Sandbox Code Playgroud)

返回值size是长度本来如果空间是可写的- 不包括终止空.

在这种情况下,如果size大于或等于5,则表示发生截断 - 如果您不想截断,则可以分配新字符串并重试snprintf().

char *x = malloc(BUF_LEN * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56");
if (size >= BUF_LEN) {
    realloc(&x,(size + 1) * sizeof(char));
    snprintf(x, size + 1 , "%s%s%s", "12", "34", "56");
}
Run Code Online (Sandbox Code Playgroud)

(这是一个非常天真的算法,但它说明了这一点)

asprintf() 为您执行此操作 - 计算字符串的长度,分配该内存量,并将字符串写入其中.

char *x;
int size = asprintf(&x, "%s%s%s", "12", "34", "56");
Run Code Online (Sandbox Code Playgroud)

在所有情况下,一旦你完成了x你需要释放它,或者你泄漏内存:

free(x);
Run Code Online (Sandbox Code Playgroud)

asprintf()是一个隐含的malloc(),所以你必须检查它是否有效,就像你使用malloc()或任何其他系统调用一样.

if (size == -1 ) {
   /* deal with error in some way */
}
Run Code Online (Sandbox Code Playgroud)

请注意,它asprintf()是libc的GNU和BSD扩展的一部分 - 您无法确定它是否可在每个C环境中使用.sprintf()并且snprintf()是POSIX和C99标准的一部分.

  • 值得注意的是,asprintf不是C或POSIX标准的一部分,并且是GCC和BSD扩展.虽然有用 - 这就是问题所在 - 但应该充分意识到你的C代码的可移植性已经下降了.http://linux.die.net/man/3/asprintf (3认同)
  • 另外,[你不应该在 C 中转换 `malloc`(和家族)的结果](http://www.stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc)。 (2认同)

Aln*_*tak 20

好处是安全.

许多程序通过在填充用户提供的数据时使程序员提供的缓冲区溢出来允许系统漏洞发生.

asprintf分配的缓冲区,你保证不能发生.

但是,您必须检查返回值asprintf以确保内存分配实际成功.见http://blogs.23.nu/ilja/2006/10/antville-12995/

  • @BrandonLing:它删除了代码重复 - 很多时候当你想要一个永不截断的`sprintf`时,你不得不编写你自己的函数来做到这一点,所以现在你把它全部包裹在一个单一的,现成的功能,以便携性为代价. (6认同)
  • @Brandon很好,在很多情况下它也会让你的代码更短! (2认同)