为什么要在snprintf的第二个参数中加1或2?

时间:2011-07-18 06:31:27

标签: c qt

12在这些snprintf函数中的作用是什么?任何人都可以解释一下

snprintf(argv[arg++], strlen(pbase) + 2 + strlen("ivlpp"), "%s%ccivlpp", pbase, sep);
snprintf(argv[arg++], strlen(defines_path) + 1, "-F\"%s\"", defines_path);

3 个答案:

答案 0 :(得分:3)

+2的作用是允许终端为null,并且%c格式的嵌入字符为,因此格式化第一个字符串的空间恰好合适。 但是(正如6502指出的那样),提供的实际字符串是一个比所需短的空格,因为strlen("ivlpp")与格式本身的civlpp不匹配。这意味着最后一个字符(第二个'p')将在输出中被截断。

+1的作用也是导致snprintf()截断格式化数据。格式字符串包含4个文字字符,您需要允许终端为null,因此代码应分配strlen(defines)+5。实际上,snprintf()会截断数据,不会有4个字符。

我怀疑代码是否真的可靠...内存分配没有显示,但必须非常复杂 - 或者必须过度分配以确保没有缓冲区溢出的危险


由于OP的评论说:

  

我不知道使用snprintf()

int snprintf(char *restrict s, size_t n, const char *restrict format, ...);

snprintf()函数格式化printf()之类的数据,但它将其写入字符串(名称中的s)而不是文件。名称中的第一个n表示函数被准确地告知字符串有多长,因此snprintf()确保输出数据为空终止(除非长度为0)。它会报告字符串应该有多长;如果报告的值超过提供的值,则表示数据已被截断。

因此,总的来说,snprintf()是一种相对安全的格式化字符串的方法,前提是您正确使用它。问题中的示例并未演示“正确使用它”。

一个问题:如果你在MS Windows上工作,请注意snprintf()的MSVC实现并不完全符合C99标准(看起来好像MS不再提供snprintf()所有;只有_snprintf()等各种替代方案。我忘记了确切的偏差,但我认为这意味着当字符串长度超过所提供的空间时,字符串在所有情况下都不会被正确地终止。

使用本地定义的数组,通常使用:

nbytes = snprintf(buffer, sizeof(buffer), "format...", ...);

使用动态分配的内存,通常使用:

nbytes = snprintf(dynbuffer, dynbuffsize, "format...", ...);

在这两种情况下,检查nbytes是否包含小于size参数的非负值;如果是的话,你的数据还可以;如果该值等于或大于,则您的数据被切断(并且您知道需要分配多少空间)。

C99标准说:

  

snprintf函数返回已写入的字符数   已n足够大,不计算终止空字符,或负数   如果发生编码错误,则为value。因此,空终止输出已经   当且仅当返回的值是非负且小于n时才完全写入。

答案 1 :(得分:2)

您正在阅读其代码的程序员不知道如何正确使用snprintf。第二个参数是缓冲区大小,所以它几乎总是这样:

snprintf(buf, sizeof buf, "..." ...);

以上是buf是数组而不是指针的情况。在后一种情况下,您必须传递缓冲区大小:

snprintf(buf, bufsize, "...", ...);

不需要计算缓冲区大小。

顺便说一句,因为您将问题标记为与qt相关。有一个非常好的QString类,你应该使用它。

答案 2 :(得分:0)

初看起来似乎都不正确。

  1. 在第一种情况下,正确的计算将是path + sep + name + NUL,所以2似乎没问题,但是对于名称,strlen调用正在使用ilvpp,而格式代码正在使用{{1这是一个更长的字符。

  2. 在第二种情况下,添加的字符数为4(cilvpp)因此,由于结尾NUL,要添加的数字应为5。