作业:创建我自己的memcpy。为什么将目标和源指针转换为 unsigned char* 而不是 char*?

Lea*_*ode 6 c memset memcpy

我正在尝试创建我自己的 C 函数版本,当我到达时,memcpymemset认为我应该将目标和源指针转换为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是你想要的,所以即使没有严格要求,人们也倾向于默认它。


Lun*_*din 7

在这个具体案例中没有什么特别的原因,主要是风格上的。

但一般来说,在处理原始数据时最好坚持使用无符号算术。即:unsigned charuint8_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% 的所有用例中都是毫无意义的膨胀。

  • @JohnBollinger看看C在类型兼容性、类型限定符、对齐、严格别名、字节序、空指针、空指针、函数指针、转换结构的特殊规则等方面有多少陷阱,初学者最好不要去那里所有国际海事组织。仅在您的私人语言律师在场的情况下才进行铸造。您有权不进行投射。你使用的任何演员都可能或将会被用来对付你。:) (3认同)