【问题标题】:ASCII value is greater than 127ASCII 值大于 127
【发布时间】:2021-06-05 02:09:06
【问题描述】:
#include <stdio.h> 
  
int main() { 
    char c = 125; 
  
    c = c + 10; 
  
    printf("%d", c); 
  
    return 0; 
}

这段代码的输出是-121

这个输出是-121?能解释一下吗?

如果我用c 添加100 而不是10,则输出为-31。 为什么?

【问题讨论】:

  • char,没有signedunsigned 可以是其中之一。在您的平台上,char 已签名,因此您会进行签名溢出,这是未定义的行为。此外,您应该使用格式字符串"%hhd"
  • @ThomasJager:没有未定义的行为。 c+ 10 中的加法是在 int 类型中执行的,因此不会溢出;它产生 135。赋值 c = c+ 10; 将其转换为 char。根据 C 2018 6.3.1.3 3,转换是实现定义的。
  • @EricPostpischil 好点,没想到。
  • Mujahidul Islam,没有 ASCII 值 > 127。ASCII 值范围从 0 到 127。char 可以编码所有 128 个 ASCII 值以及其他非 ASCII 值。

标签: c char ascii


【解决方案1】:

在 C 语言中,char 类型是一个 整数 类型,能够表示语言本身所需的所有字符。该标准没有指定它是有符号类型还是无符号类型。看到输出后,我猜你的系统使用了一个大小为 8 位(7 个值位和一个符号位)的有符号字符,并在 2-补码中表示负值。

所以(作为 int)125 + 10 = 135。135 > 128 所以实际值为 135 - 256 = -121。

(在两个补码模式下,数字只是包裹在 2**SIZE_IN_BITS...)

【讨论】:

  • 谢谢。我认为这就是其背后的主要逻辑。
  • 用 2-complement 表示负值是什么让你推断出这个?
  • @chqrlie:2-补码现在是最常见的模式,而 125+10 给出 -121 的事实。
  • 这确实是一个有争议的问题,因为 OP 和大多数读者除了一个 8 位字节的标准 CPU 之外从未见过任何东西,默认情况下碰巧签署了 char。在这样的架构上,当将 135 存储到有符号的 8 位字符 c 中时,结果要么是实现定义的,要么会引发实现定义的信号。 (C17 6.3.1.3) .因此,尽管您的解释与观察到的行为一致,但无法从实际存储的值中推断出多少。
  • @chqrlie:我已经足够大,可以记住具有 12 位字符的体系结构(即使我没有 C 编译器......)。但我希望有人现在使用非 8 位字符来清楚地说明它,因为它相当不常见......但我可能对提问者过于自信......
【解决方案2】:

它的工作原理是编译器中的 char 类型是一个 8 位宽的有符号类型,并使用称为二进制补码的系统表示整数值。

在这个系统中,正值以二进制形式从 0 到 127,如下所示:

00000000   0
00000001   1
00000010   2
00000011   3
     ...   .
01111111 - 127

在下一次递增时,最高位翻转为 1:我们得到10000000。然后后续的二进制值在二进制补码下被解释为负数:

10000000   128    -128
10000001   129    -127
10000010   130    -126
     ...
11111111   255      -1

中间一列,从 128 继续往上计数,显示 8 位数据的无符号解释;它只是一直向 255 计数。这将是 unsigned char 类型的行为。

右列显示负数,是对完全相同的位模式的二进制补码解释。相反,它涵盖了从 -128 到 -1 的负整数范围。

现在,当我们执行c + 10 时,C 中会发生什么?

首先,根据C语言的规则,char类型的c值被提升为int类型,其范围要大得多。因此,int 的值 125 被添加到 int 的值 10,从而得到 int 的值 135。

接下来会发生c 被赋予该值,就像c = 135 一样。但是135不在范围内; char 仅上升到 127实现定义的行为随之而来。 135 值通过丢弃位以某种方式强制适应。

二进制补码机器的 C 编译器(即地球上几乎所有的编译器)只需截断值的底部位以适应较小的类型,即可将较宽的整数值截断为较窄的值。 p>

所以,135的二进制表示是这样的。

 10000111

更准确地说,假设int 是 32 位宽。那么int值135的表示为:

 00000000000000000000000010000111

通过切掉前 24 位,保留后 8 位,将其转换为 char:

 ------------------------10000111    

所以我们结束了

 10000111

char 类型中。但那是什么?参考我们的原始表格,我们可以再添加几行:

10000000   128    -128
10000001   129    -127
10000010   130    -126
10000011   131    -125
10000100   132    -124
10000101   133    -123 
10000110   134    -122
10000111   135    -121 <----
     ...
11111111   255      -1

还有 -121。

【讨论】:

    【解决方案3】:

    char 类型在内存中表示为 byte(大多数情况下为 8 位),因此它可以表示从 -128+127 的值。如果您尝试在内存中存储更大的值,则会导致溢出,结果与预期不符。

    Here 是一个很好的视频,解释了什么是溢出。

    【讨论】:

      【解决方案4】:

      char 是 8 位的一个字节。一位是符号,7位是你可以使用的。

      “char”范围是: 字符 ==> -128 ~ 127

      static_cast<char>(c+1)  = 126
      static_cast<char>(c+2)  = 127
      static_cast<char>(c+3)  = -128
      
      

      如果你使用 from "unsigned char",正数范围会增加。

      无符号字符 ==> 0 ~ 255

      static_cast<unsigned char>(c+3) = 128
      

      【讨论】:

      • C 标准允许对char 进行签名或未签名。
      • 一个字节(在 C 中又称为“char”)不一定是 8 位。
      • @SergeBallesta 发布此答案时标记为 C++。
      猜你喜欢
      • 2014-06-20
      • 2011-09-15
      • 1970-01-01
      • 2021-12-31
      • 2021-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多