通过阅读strlcpy的人我遇到了例子:
Since it is known how many characters were copied the first time,
things can be sped up a bit by using a copy instead of an append:
char *dir, *file, pname[MAXPATHLEN];
size_t n;
...
n = strlcpy(pname, dir, sizeof(pname));
if (n >= sizeof(pname))
goto toolong;
if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n)
goto toolong;
However, one may question the validity of such optimizations,
as they defeat the whole purpose of strlcpy() and strlcat().
As a matter of fact, the first version of this manual page got it wrong.
什么是
whole purpose of strlcpy
以及上述示例 defeats
究竟如何?
还有
the first version of this manual page
中的内容以及为什么在新的内容中提及它仍然很重要?
strlcpy 的目的是什么?
strncpy
和strlcpy
都保证不会尝试写入超出第三个参数给定的长度,但它们在副本超出缓冲区时处理最后一个字符的方式不同:
strncpy
将一个字符从源复制到目标的最后一个字节。strlcpy
将空字符写入目标的最后一个字节。strncpy
可以想象有一些用途,例如完全填充目标缓冲区,然后,如果源未完全复制,则使用 realloc
为目标分配更多内存,然后完成操作。然而,它可能容易被误用:由于它产生的输出不是以 null 结尾的,因此使用字符串编写代码的程序员可能会无意中将目标视为以 null 结尾的字符串,将其传递给 printf
或其他例程,从而导致崩溃或其他错误。
strlcpy
提供了一些针对此类错误的安全性,因为它的输出始终是一个以 null 结尾的字符串。 (当然,可能会出现不同类型的错误,例如由于缺少预期部分或因为它比预期短而产生不正确的字符串。)
...其手册页的第一个版本中包含哪些内容?
正如手册页指出的那样,替换此代码:
if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname))
goto toolong;
if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
goto toolong;
使用此代码:
n = strlcpy(pname, dir, sizeof(pname));
if (n >= sizeof(pname))
goto toolong;
if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n)
goto toolong;
可以提高效率,但有引入错误的危险,我们可以假设第一个版本的手册页在比较(
n >= sizeof(pname)
或strlcpy(…) >= sizeof(pname) - n
)或长度和地址计算(pname + n
,sizeof(pname) - n
)中存在错误
)。可能使用 >
代替 >=
或 n-1
代替 n
或其他一些差一错误。具体错误无关紧要;关键是更复杂的代码更容易出现人为错误。
什么是
以及上述示例the whole purpose of strlcpy
究竟如何?defeats
这个问题误解了手册评论的重点,这表明在这种情况下
strlcpy()
应与 strlcat()
一起使用(避开假定的优化),如前面的示例所示。引用的例子并没有违背strlcpy()
的目的。它违背了 strlcpy()
和 strlcat()
作为一对的目的。
当为此目的一起使用时,对
strlcpy()
或 strlcat()
的每次调用都将传递一个指向目标缓冲区的整体开始位置和缓冲区的完整大小的指针。这使程序员无需跟踪和使用有关目标字符串当前长度的信息,而这可能是错误的根源。它提供了执行此操作的能力,手册将其称为这对函数的全部目的,尽管这有点夸张。
还有
中的内容以及为什么在新的内容中提及它仍然很重要?the first version of this manual page
具体细节尚不清楚,但总的一点是,该示例中页面的原始版本包含错误,而正是
strlcat()
和 strlcpy()
的推荐使用模式旨在避免的错误。也就是说,维护目标字符串的长度或正确使用目标字符串时出现错误。
但对于实际提出的第一个问题,
strlcpy()
作为单个函数的主要目的是提供strncpy()
的变体,以保证以NUL结尾目标字符串。然而,这有点转移注意力,因为 strncpy()
本身就是一个。外行人很容易误认为它更安全strcpy()
,但事实上,它只适用于某些非常特殊的用途。其实是strncat()
更安全strcpy()
:
#define safer_strcpy(dest, src, size) (*(dest) = '\0', strncat(dest, src, size))