strlcat(): dst是否总是以NUL结尾?“size”和返回值是什么?

7

我需要实现自己的strlcat()函数,这是标准C库中的一个函数,用于操作字符串。

size_t     strlcat(char * restrict dst, const char * restrict src, size_t size);

关于它的工作方式,我有两个问题:

在每种情况下,它是否NUL_终止dst

我的man页上写着:

strlcat()使用缓冲区的完整大小(而不仅仅是长度),并保证将结果NUL结尾(只要size大于0或者在strlcat()的情况下,dst中至少还有一个字节的空闲)。

并且:

strlcat()函数将NUL结尾字符串src附加到dst的末尾。它最多附加size - strlen(dst) - 1字节,并在结尾处添加NUL。

但也有这样的描述:

请注意,如果strlcat()查找size个字符而没有找到NUL,则认为字符串的长度为size,并且目标字符串将不会NUL结尾(因为没有空间放置NUL)。

那么,在每种情况下,我是否需要NUL_终止dst? 一方面,它说有一种情况下dst字符串不是NUL_终止的。 另一方面,手册说strlcat()保证dst将被NUL_终止,而不NUL_终止的字符串会很不安全,不是吗?

请问有人能举个例子吗?

返回值代表什么?为什么会有这种行为?

这里是我进行一些测试时得到的结果:

Before :                || After :
dst   | src   | size    || dst      | return
------------------------||--------------------
dst\0 | src\0 | 0       || dst\0    | 3
dst\0 | src\0 | 1       || dst\0    | 4
dst\0 | src\0 | 2       || dst\0    | 5
dst\0 | src\0 | 3       || dst\0    | 6
dst\0 | src\0 | 4       || dst\0    | 6
dst\0 | src\0 | 5       || dsts\0   | 6
dst\0 | src\0 | 6       || dstsr\0  | 6
dst\0 | src\0 | 7       || dstsrc\0 | 6
dst\0 | src\0 | 8       || dstsrc\0 | 6

再次来自这位先生:

[strlcat()函数]返回它试图创建的字符串的总长度。对于strlcat()函数,这意味着dst的初始长度加上src的长度。

在我的测试中,dstsrc的大小是恒定的(3和3)。那么为什么有时返回值与6不同?

难道不应该是(len(dst) + min(size, len(src))吗?

size代表什么?

strlcat()函数将以NUL结尾的字符串src附加到dst的末尾。它最多会附加size - strlen(dst) - 1字节,以NUL结尾的结果。

所以,size应该是允许dst末尾的长度(包括'\0'字符)吗?是这样吗?


“在所有情况下,它是否都会以NUL结尾dst?” 不要根据下面第三段问这个问题。如果您必须实现它,我建议它应该按照文档中描述的行为。 - Weather Vane
strlcat 不在标准 C 中。 - M.M
@M.M 我不知道,如果我运行man strlcat,在“库部分”中会有这个:标准C库(libc,-lc) - vmonteco
@vmonteco 术语不当。请查看C标准以了解标准C中的内容。 - M.M
2个回答

8

1. strlcat是否总是将dst截断并以null结尾?

如果strlcat修改了dst,则dst将以null结尾。如果dst已经完全占用,strlcat不会修改dst。如果在dst的前size - 1个字节中未找到NUL(或者size为0),则认为dst已完全占用。

因此,有两种情况下strlcat不会使dst以null结尾。一种情况是dst是一个刚好有size - 1个字节的以null结尾的字符串,在这种情况下它不会被修改且仍然以null结尾。第二种情况是dst最初没有以null结尾,在这种情况下,调用strlcat后它仍然未以null结尾。

2. 如何测量原始目标字符串的长度?

size应该是包含dst的内存区域的大小,因此假设dst[size]是无效的内存引用。因此,如果dst最初是一个有效的(因此以null结尾)字符串,则其长度将严格小于size,并且strlcat会将strlen(dst)作为其长度。如果dst无效,则假定其大小为size,这种情况下dst不会被修改。见上方。


这很清楚,谢谢!但是您可以确认(或否定)我对返回值的猜测吗? :) - vmonteco
2
@vmonteco:我认为从我的回答中可以看出来。它是 min(size, strlen(dst)) + strlen(src),理解它只查看最多 size 个字符来计算左侧表达式。 - rici

0
我认为返回的值应该是strnlen(dst) + strlen(src)而不是min(size, strlen(dst)) + strlen(src)。这是因为当dst没有以null结尾时,strlen(dst)会访问无效的内存。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接