我尝试创建一个函数strlcpy
,我将其命名为ft_strlcpy
。我的函数是否像这样工作strlcpy
?
size_t ft_strlcpy(char *dst, const char *src, size_t dstsize)
{
size_t len;
len = ft_strlen(src);
if (dstsize)
{
while (dstsize-- > 1 && *src)
*dst++ = *src++;
*dst = '\0';
}
return (len);
}
我尝试询问claud ai,但是它告诉我功能不完全相同。
9
最佳答案
2
以下是原始 BSD 手册页中关于strlcpy
(和)的规范:strlcat
概要
#include <bsd/string.h> size_t strlcpy(char *dst, const char *src, size_t size); size_t strlcat(char *dst, const char *src, size_t size);
描述
strlcpy()
和函数strlcat()
分别复制和连接字符串。它们旨在成为strncpy(3)
和 的更安全、更一致、更不容易出错的替代品strncat(3)
。与那些函数不同,strlcpy()
和strlcat()
占用缓冲区的完整大小(而不仅仅是长度)并保证以 NUL 终止结果(只要 size 大于 0,或者在 的情况下strlcat()
,只要 中至少有一个可用字节dst
)。请注意,NUL 的字节应包含在 size 中。另请注意strlcpy()
和strlcat()
仅对真正的“C”字符串进行操作。这意味着strlcpy()
src
必须以 NUL 终止,并且和strlcat()
都必须以 NUL 终止。src
dst
该函数从以 NUL 结尾的字符串复制
strlcpy()
最多个字符到,并以 NUL 结尾的结果。size - 1
src
dst
该
strlcat()
函数将以 NUL 结尾的字符串附加src
到 的末尾dst
。它将附加最多size - strlen(dst) - 1
字节,并以 NUL 结尾结果。返回值
strlcpy()
和函数strlcat()
返回它们尝试创建的字符串的总长度。对于 ,strlcpy()
这意味着 的长度src
。对于,strlcat()
这意味着 的初始长度dst
加上 的长度src
。虽然这看起来有些令人困惑,但这样做是为了让截断检测变得简单。但请注意,如果
strlcat()
遍历size
字符而未找到 NUL,则字符串的长度将被视为 NULsize
,并且目标字符串将不会以 NUL 结尾(因为没有 NUL 的空间)。这可以防止strlcat()
超出字符串的末尾。实际上,这种情况不应该发生(因为这意味着 是size
错误的,或者dst
不是一个正确的“C”字符串)。检查是为了防止错误代码中出现潜在的安全问题。
现在关于你的问题:我的功能是否像strlcpy
?:
- 它确实会返回
strlen(src)
- 它复制的字符不超过从 到 NUL 终止符的
dstsize-1
字符。src
- 它会以 NUL 终止
dst
,前提dstsize
是 不是0
。
您对第三个参数使用了不同的名称,但这并没有带来功能上的差异。
但请注意,您没有提供 的源代码ft_strlen
,只能假定它返回字符串的长度,即:表现得像strlen
。
因此,从我的分析来看,您的函数确实表现得像strlcpy
。无论您要求的建议是什么,它似乎都是不正确的,如果您这样告诉它,它可能会同意并告诉您原因。
@pmg 评论说 POSIX 标准化版本的规范与strlcpy
中指定的略有不同:
#include <string.h>
size_t strlcat(char *restrict dst, const char *restrict src,
size_t dstsize);
size_t strlcpy(char *restrict dst, const char *restrict src,
size_t dstsize);
限定符restrict
告诉编译器关于参数的附加约束,指定为如果在重叠的对象之间进行复制,则行为未定义。 这允许编译器假定通过执行的修改dst
不能更改通过访问的字节src
。
这本身不会改变实现的行为,BSD 手册页中未指定源区域和目标区域重叠的情况,这可能会造成混淆或错误的预期。
可能引发混乱的是你不寻常的循环
while (dstsize-- > 1 && *src)
*dst++ = *src++;
虽然正确,但可以写成更易读的风格
// copy no more than dstsize - 1 bytes from NUL-terminated src
// note: dstsize is known to be > 0
for (size_t count = 0; count < dstsize - 1 && *src; count++)
*dst++ = *src++;
一些有创造力的人甚至可能更喜欢:
while (dstsize --> 1 && *src)
*dst++ = *src++;
的话题。
另一点是您的实现读取源字符串两次:一次测量长度,第二次至少部分复制适合目标区域的部分。虽然这对调用者来说不是一个可见的差异,但可以说这种 2 遍方法效率低下。以下是使用单遍的替代方法:
size_t ft_strlcpy(char *dst, const char *src, size_t dstsize)
{
size_t i = 0;
if (dstsize) {
// copy no more than dstsize - 1 bytes
while (i < dstsize - 1) {
char c = src[i];
dst[i] = c;
// early stop if the string fits in the destination
if (c == '\0')
return i;
i++;
}
dst[i] = '\0';
}
// count the remaining bytes in the source string
while (src[i] != '\0')
i++;
return i;
}
1
-
关于“读取源字符串两次”的观点很好。
–
|
我希望ft_strlcpy()
使用restrict
指针来指示重叠内存存在未定义行为(UB)的风险。
size_t ft_strlcpy(char *restrict dst, const char *restrict src, size_t dstsize);
如果代码确实要在没有restrict
(的情况下工作,src
并且dst
可能指向重叠区域),那么请使用初始的len
。OP 的代码,按原样,在dst == src + 1
等情况下会遇到麻烦。
size_t ft_strlcpy(char *dst, const char *src, size_t dstsize) {
size_t len = ft_strlen(src);
if (dstsize > 0) {
size_t copy = min(len, dstsize - 1);
memmove(dst, src, copy); // Handles overlapping memory.
dst[copy] = '\0';
}
return len;
}
2
-
1良好的替代实现,完全定义了重叠区域。在 OP 的上下文中(42、Epitech、Epita…),
memmove
可能不允许,但他们可以使用自己的重新实现ft_memmove
,但根据 C 标准,以完全定义的方式编写它出奇地困难。
–
-
1同意_出乎意料的困难_。
–
|
–
–
memcmp
来检查结果。–
strlcpy
,并由此得出结论,你的函数并不完全相同。除此之外,(假设size_t (*ft_strlen)(const char*) = strlen;
),我无法发现结果有什么不同–
restrict
。–
|