根据 man 3 memccpy
,memccpy
函数定义如下:
SYNOPSIS
#include <string.h> void *memccpy(void *dest, const void *src, int c, size_t n);
DESCRIPTION
memccpy()
函数将不超过n
个字节从内存区域src
复制到内存区域dest
,当找到字符c
。如果内存区域重叠,则结果未定义。
令我困惑的是 memccpy
复制 n
字节并在找到字符 c
时停止。但是,该函数将 int c
作为参数。那么如果我用下面的 value 调用 memccpy
会发生什么:
memccpy(&x, &y, 0xffffff76, 100);
这里要检查的 value 对于 char
来说太大了。这个案子应该管用吗?
回答1
memccpy()
由 POSIX.1-2001 (https://pubs.opengroup.org/onlinepubs/009695399/) 定义,其中规定:
SYNOPSIS
#include <string.h> void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n);
DESCRIPTION
memccpy()
函数应将字节从内存区域s2
复制到s1
,在第一次出现字节(转换为无符号字符)被复制,或在复制 n 个字节后,以先到者为准。如果复制发生在重叠的对象之间,则行为未定义。
所以你去,一个简单的 unsigned char
转换发生:
void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n) {
unsigned char actual_c = (unsigned char)c;
// ...
}
事实上,我所知道的最突出的 C standard library 实现正是这样做的:
- https://sourceware.org/git/?p=glibc.git;a=blob;f=string/memccpy.c;h=40ea81dcb606ef06bfbf61de279265b03a85d8e1;hb=HEAD#l31:传递给执行
unsigned char c = (unsigned int)c_in;
的memchr
- https://svnweb.freebsd.org/base/head/lib/libc/string/memccpy.c?view=markup#l41:
unsigned char uc = c;
- https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/upstream-openbsd/lib/libc/string/memccpy.c#35 (Android): 借自 BSD
unsigned char uc = c;
- https://git.musl-libc.org/cgit/musl/tree/src/string/memccpy.c#n10:使用演员表重新分配
c = (unsigned char)c;
- https://git.uclibc.org/uClibc/tree/libc/string/memccpy.c#n12:在比较时强制转换:
(((unsigned char)(*r1++ = *r2++)) != ((unsigned char) c))
回答2
这种情况在代码中究竟是如何处理的
只是将参数的 value 转换为字符:
void *memccpy(..., int param_c, ...) {
unsigned char c = param_c;
在现实生活中:https://github.com/lattera/glibc/blob/master/string/memccpy.c#L33 https://github.com/lattera/glibc/blob/master/string/memchr.c#L63 。
(在现在的系统上)unsigned char
有 8 位,(unsigned char)(int)0xffffff76
只是变成 0x76
。高位被忽略。
回答3
这是一个较旧的函数,在接受的参数方面类似于 memset
:
void *memset(void *s, int c, size_t n);
在 C 标准中是这样描述的:
memset
函数将c
的 value(转换为unsigned char
)复制到s
指向的对象的前n
字符中。
两个函数 date 至少回到 4.3 BSD,因此它们以类似的方式处理它们的参数是有意义的。
因此,根据您的示例,value 0xffffff76 将转换为 unsigned char
value 0x76,这将是它检查要停止的 value。