出于教育目的(是42是),我正在重写strncmp,一个同学走近我,问我为什么要以这种方式转换返回值。我的建议是先打字,然后再取消引用。我的逻辑是我想将char字符串视为未签名的char字符串,然后将其取消引用。

int strncmp(const char *s1, const char *s2, size_t n)
{
    if (n == 0)
        return (0);
    while (*s1 == *s2 && *s1 && n > 1)
    {
        n--;
        s1++;
        s2++;
    }
    return (*(unsigned char *)s1 - *(unsigned char *)s2);
}

他首先要取消引用,然后再进行类型转换,以确保绝对返回两个未签名字符之间的差异。像这样:
return ((unsigned char)*s1 - (unsigned char)*s2);

讨论之后(我同意他的说法,我很奇怪),我们查找了一些可用于生产的实现的源代码,令我们惊讶的是,Apple似乎按照与我相同的顺序进行了类型转换/取消引用:

https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/i386.subproj/strncmp.c.auto.html

因此,问题是:在这种情况下有什么区别?为什么选择一个呢?

(我已经找到了以下内容;但是它指定了不同大小的数据类型的强制转换/取消引用,但是对于chars/unsigned chars来说,应该没关系吗?

In C, if I cast & dereference a pointer, does it matter which one I do first?)

最佳答案

的二进制补码系统上(几乎全部都是),它不会有所作为。
第一个示例*(unsigned char *)x会简单地将存储在该位置的数据的二进制值解释为unsigned char,因此,如果存储在该位置的十进制值为-1,则存储的十六进制值(假设CHAR_BIT = 8)是0xFF,那么它会被简单地解释为255,因为它适合十六进制表示形式。
第二个示例(假设char在此编译器上签名)-(unsigned char)*x-将首先获取存储在该位置的值,然后将其强制转换为unsigned。因此,我们得到了-1,并将其转换为unsigned char,该标准指出,要将负有符号数转换为无符号值,您需要向该负值添加比该类型可存储的最大值多一个的值,直到您拥有一个值在其范围内。所以你得到-1 + 256 = 255但是,如果您以某种方式使用的补充系统,则情况会有所不同。
同样,使用*(unsigned char *)x,我们将-1的十六进制表示形式重新解释为unsigned char,但是这次的十六进制表示形式是0xFE,它将被解释为254而不是255
回到(unsigned char)*x,仍然需要执行-1 + 256来获得255的最终结果。
综上所述,我不确定char的第8位是否可以由C标准的字符编码使用。我知道在ASCII编码的字符串中不使用它,这也是您很可能会使用的字符串,因此在比较实际的字符串时,您可能不会遇到任何负值。

从有符号到无符号的转换可以在C11标准的6.3.1.3节中找到:

关于c - 返回char字符串的指针之间的差时,强制转换和取消引用的顺序有多重要?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58924371/

10-17 02:03