我正在尝试创建我自己的 C 函数版本,当我到达时,memcpy我memset认为我应该将目标和源指针转换为char *. 然而,我见过很多指针被转换到的例子unsigned char *。这是为什么?
void *mem_cpy(void *dest, const void *src, size_t n) {
if (dest == NULL || src == NULL)
return NULL;
int i = 0;
char *dest_arr = (char *)dest;
char *src_arr = (char *)src;
while (i < n) {
dest_arr[i] = src_arr[i];
i++;
}
return dest;
}
Run Code Online (Sandbox Code Playgroud)
Sha*_*ger 11
对于这种情况并不重要,但是许多使用原始字节的人更喜欢显式指定unsigned char(或使用stdint.h类型,uint8_t)以避免在必须对字节进行数学运算时出现奇怪的情况。char具有实现定义的有符号性,这意味着,当应用整数提升和通常的算术转换时,char具有高位集的 a 如果有符号则被视为负数,如果无符号则被视为正数。
虽然对于给定的问题,这两种行为都不一定是错误的,但事实上,行为可能会在编译器之间发生变化,甚至在同一编译器上设置不同的标志,这意味着您经常需要明确符号性,使用或signed char适当unsigned char,并且 99%有时,行为unsigned char是你想要的,所以即使没有严格要求,人们也倾向于默认它。
在这个具体案例中没有什么特别的原因,主要是风格上的。
但一般来说,在处理原始数据时最好坚持使用无符号算术。即:unsigned char或uint8_t。
该char类型是有问题的,因为它具有实现定义的符号性,因此在此类代码中应避免使用。char 默认是有符号的还是无符号的?
注意:这是危险且糟糕的风格:
char *src_arr = (char *)src;
Run Code Online (Sandbox Code Playgroud)
(演员们把问题隐藏在地毯下面)
由于您正确使用了“const正确性” src,因此正确的类型是:const char *src_arr;我将代码更改为:
unsigned char *dest_arr = dest;
const unsigned char *src_arr = src;
Run Code Online (Sandbox Code Playgroud)
对于初学者来说,一个好的经验法则是永远不要使用石膏。我是认真的。我们在初级程序中看到的 SO 中大约 90% 的演员表都是错误的,无论是哪种方式。
memcpy顺便说一句(高级主题)原型如下是有原因的:
void *memcpy(void * restrict s1,
const void * restrict s2,
size_t n);
Run Code Online (Sandbox Code Playgroud)
指针上的限定符restrict告诉函数的用户“嘿,我指望你不要将两个指针传递给同一对象或可能重叠的指针”。这样做会在各种情况下和不同的目标上引起问题,所以这是一个好主意。
用户传递重叠指针的可能性比传递空指针的可能性大得多,因此,如果您要对 进行缓慢、多余的错误检查NULL,则还应该restrict限定指针。
如果用户传递空指针,我只会让函数崩溃,而不是使用额外的分支来减慢速度,这些分支在 99% 的所有用例中都是毫无意义的膨胀。