转换的区别:char与unsigned char

hsvhsicv  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(110)

在这个函数中,为什么我们需要用unsigned char进行转换?我们不能用char进行转换并得到相同的结果吗?因为两者的范围都是“255”?为什么选择unsigned char?
假设没有ASCII码等于-126。我可以说255也是一样的;两者都会给予你一个垃圾值。如果你告诉我我们选择它是因为我们正在处理字节,它的最大值是255,我会说我们只是在比较。所以,在s1和s2中,结果总是ASCII码。为什么我们选择无符号字符?

#include "libft.h"

int ft_strncmp(const char *s1, const char *s2, size_t n)
{
    size_t  i;

    i = 0;
    if (n == 0)
        return (0);
    while (i < n && (s1[i] != '\0' || s2[i] != '\0'))
    {
        if (s1[i] != s2[i])
            return ((unsigned char)s1[i] - (unsigned char)s2[i]);
        i++;
    }
    return (0);
}

字符串

fd3cxomn

fd3cxomn1#

在这个函数中,为什么我们需要用unsigned char进行强制转换?
因为该函数复制了标准库函数strncmp()的行为,该函数比较参数的字节,就好像它们具有unsigned char类型一样。
我们不能用char进行强制转换并得到相同的结果吗?因为两者的范围都是“255”。
C语言规范明确允许char具有与unsigned charsigned char相同的范围和行为,后者非常常见。在signed char等价的情况下(假设8位字节,这在C23之前没有保证),char的范围是-128到127。
您仍然可以使用char类型进行比较,但是在某些系统上会产生与其他系统不同的结果。
(Also:元素已经是char s。在该类型中不需要强制转换来进行比较。)
为什么选择unsigned char?
这是因为unsigned char可以产生所需的顺序,而char可能不会,而且因为使用unsigned char可以在不同的实现中产生一致的顺序,即使你想实现一个不同的顺序。
假设没有ASCII码等于-126,我可以说255也是如此;两者都会给你一个给予垃圾值。
ASCII与此关系不大。C并不假定char值是特定的ASCII码。运行时字符集可能与ASCII不同或不兼容--比如说EBCDIC--今天使用的机器就是这种情况。这里没有假设或依赖任何特定的字符集。

ljo96ir5

ljo96ir52#

标准C库执行 string 函数,就好像字符是unsigned char一样。
对于本小节中的所有函数,每个字符都应该被解释为具有unsigned char类型(因此每个可能的对象表示都是有效的,并且具有不同的值)。
由于char可能是 signedunsigned,当char之一为负时,减去2 char与2 unsigned char的结果不同。因此转换为unsigned char形成了类似C库的差异。

学究气

  • 在极少数实现中,charint的宽度是相同的,因此通过减法来返回具有正确符号的差值有溢出的风险。
  • 对于 * 字符串 * 和几乎过时的非2补码格式,((unsigned char *)s1)[i]可以与(unsigned char)s1[i]不同,并且是首选格式。

下面解决这两个问题:

int ft_strncmp(const char *s1, const char *s2, size_t n) {
  const unsigned char *u1 = (const unsigned char *)s1;
  const unsigned char *u2 = (const unsigned char *)s2;
  size_t  i = 0;
  // if (n == 0)      // Not needed
  //    return (0);
  while (i < n && (u1[i] != '\0' || u2[i] != '\0')) {
    if (u1[i] != u2[i]) {
      return (u1[i] > u2[i]) - (u1[i] < u2[i]);
    } 
    i++;
  }
  return 0;
}

字符串

int ft_strncmp_alt(const char *s1, const char *s2, size_t n) {
  const unsigned char *u1 = (const unsigned char *)s1;
  const unsigned char *u2 = (const unsigned char *)s2;
  size_t  i = 0;
  while (i < n && (u1[i] == u2[i]) && u1[i]) {
    i++;
  }
  if (i == n) {
    return 0;
  } 
  return (u1[i] > u2[i]) - (u1[i] < u2[i]);
}

vmpqdwk3

vmpqdwk33#

在这种情况下,unsigned char的使用与字符比较的工作方式有关,特别是在处理ASCII范围之外的字符时。
在C标准中,像memcmp和strcmp这样的函数的行为是根据无符号字符值定义的。当你在比较之前将字符转换为无符号字符时,你要确保比较是在无符号上下文中完成的。当处理在有符号字符范围内具有负值的字符时,这一点很重要。
在您的特定示例中,转换为unsigned char用于处理当被视为有符号字符时可能具有负值的字符。这是相关的,因为标准允许字符在有符号字符表示中具有负值,并且直接将它们作为有符号字符进行比较可能不会产生正确的结果。
考虑char是有符号的,范围是-128到127。如果一个字符的值大于127(例如,255),那么当它存储在有符号的char中时,它将被视为负值。将它转换为unsigned char可以确保它在比较期间被视为正值。
通过在ft_strncmp函数中将s1[i]和s2[i]都转换为unsigned char,您明确声明比较应该在unsigned上下文中进行,避免与有符号char表示相关的问题。
因此,虽然您正确地认为ASCII范围是0到127,并且在某些上下文中可能会将127以上的值视为垃圾,但在字符比较函数中使用unsigned char是正确处理所有可能的字符值的良好实践,特别是在底层表示可能是有符号的情况下

相关问题