返回char字符串的指针之间的差时,强制转换和取消引用的顺序有多重要?

wan*_*ata 6 c casting dereference strncmp

出于教育目的(是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);
}
Run Code Online (Sandbox Code Playgroud)

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

return ((unsigned char)*s1 - (unsigned char)*s2);
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

在C语言中,如果我强制转换并取消引用一个指针,那么我首先执行哪个操作是否重要?

Chr*_*ons 4

二进制补码系统(几乎是所有补码系统)上,这不会产生任何影响。

第一个示例*(unsigned char *)x-- -- 将简单地将存储在该位置的数据的二进制值解释为unsigned char,因此,如果存储在该位置的十进制值是-1,则存储的十六进制值(假设CHAR_BIT=8)是0xFF,然后它将简单地解释为被解释为255适合十六进制表示。

第二个示例(假设char在此编译器上有符号)--(unsigned char)*x将首先获取存储在该位置的值,然后将其转换为无符号。因此,-1在将其强制转换为 时unsigned char,标准规定,要将负符号数转换为无符号值,您可以根据需要将比该类型可存储的最大值多一的负值添加到负值,直到您的值在它的范围。所以你得到-1 + 256 = 255

然而,如果你以某种方式使用补码系统,情况就会有所不同。

再次使用*(unsigned char *)x,我们将 的十六进制表示重新解释-1unsigned char,但这次十六进制表示为0xFE,它将被解释为 ,254而不是255

回过头来看(unsigned char)*x,它仍然只需要执行即可-1 + 256得到最终结果255

尽管如此,我不确定 a 的第 8 位是否char可以由 C 标准的字符编码使用。我知道它不用于 ASCII 编码的字符串,这也是您最有可能使用的字符串,因此在比较实际字符串时您可能不会遇到任何负值。


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

  1. 当一个整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新类型表示,则该值不变。

  2. 否则,如果新类型是无符号的,则通过重复加或减新类型可以表示的最大值1来转换该值,直到该值在新类型的范围内。

  • “在比较实际字符串时,您可能不会遇到任何负值” - 直到 UTF-8 语言环境中的人写出他们的母语 (2认同)