1
和2
在这些snprintf函数中的作用是什么?任何人都可以解释一下
snprintf(argv[arg++], strlen(pbase) + 2 + strlen("ivlpp"), "%s%ccivlpp", pbase, sep);
snprintf(argv[arg++], strlen(defines_path) + 1, "-F\"%s\"", defines_path);
答案 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)
初看起来似乎都不正确。
在第一种情况下,正确的计算将是path + sep + name + NUL
,所以2似乎没问题,但是对于名称,strlen调用正在使用ilvpp
,而格式代码正在使用{{1这是一个更长的字符。
在第二种情况下,添加的字符数为4(cilvpp
)因此,由于结尾NUL,要添加的数字应为5。