【问题标题】:Why 256 for a signed char is undefined in C++为什么在 C++ 中未定义有符号字符的 256
【发布时间】:2012-11-14 04:59:54
【问题描述】:

阅读 C++ Primer 5th edition book,我注意到 signed char 的值为 256 是未定义的。 我决定尝试一下,我发现std::cout 不适用于那个 char 变量。 (无印刷)。

但是在 C 上,同样的事情 signed char c = 256; 将为char c 提供一个值0

我尝试搜索但没有找到任何东西。

有人可以向我解释为什么在 C++ 中会出现这种情况吗?

编辑:我知道 256 是 2 个字节,但为什么 C++ 中的情况与 C 不同?

【问题讨论】:

  • 最大值为255,256个值从0到255。
  • 我知道,在 C 语言中也是如此,对吧? 255 仍然是最大值。但是为什么 C++ 没有发生同样的事情呢?
  • 它们是不同的语言,C 和 C++,因此有不同的约定。
  • @CodingMash,我相信 C++ 将 C 作为子集。至少大多数书籍都是这么说的。
  • 顺便说一句,它打印空字节,而不是什么

标签: c++ char signed


【解决方案1】:

这本书非常不正确。

中没有未定义的行为
signed char c = 256;

256int 类型的整数文字。要使用它初始化 signed char,将其转换为 signed char(第 8.5 节 [dcl.init]/17.8;所有引用均指向 N4140)。这种转换受 §4.7 [conv.integral] 的约束:

1 整数类型的纯右值可以转换为纯右值 另一种整数类型。无作用域枚举类型的纯右值可以是 转换为整数类型的纯右值。

2 如果目标类型是无符号的,[...]

3 如果目标类型是有符号的,如果可以,值不变 以目标类型(和位域宽度)表示; 否则,该值由实现定义。

如果 signed char 不能表示 256,则转换会产生一个类型为 signed char 的实现定义值,然后用于初始化 c。这里没有未定义的内容。


当人们说“签名溢出是 UB”时,他们通常指的是 §5 [expr]/p4 中的规则:

如果在计算表达式期间,结果不是 数学定义或不在可表示值的范围内 它的类型,行为未定义。

这会渲染像INT_MAX + 1这样的UB表达式——操作数都是ints,所以结果的类型也是int,但是值超出了可表示值的范围。这个规则在这里不适用,因为唯一的表达式是256,其类型是int,而256显然在int的可表示值范围内。

【讨论】:

  • "这会渲染像INT_MAX + 1这样的UB表达式" 这似乎不适用于常量表达式,而int i = INT_MAX + 1;是UB,使得i常量@987654338 @ 将调用隐式转换(无论INT_MAX + 1 可以适合什么类型,到int),这是实现定义的。不过,我不确定的一件事是,有符号字符和短整数如何产生整数溢出(假设 char
【解决方案2】:

编辑:请参阅下面的 T.C. 的答案。这样更好。

有符号整数溢出在 C++ 和 C 中是未定义的。在大多数实现中,signed charSCHAR_MAX 的最大值为 127,因此将 256 放入其中会溢出。大多数情况下,您会看到数字只是环绕(到 0),但这仍然是未定义的行为。

【讨论】:

  • 所以溢出不是标准行为?
  • @cprogcr 不,一点也不。 unsigned 数字可以保证环绕。
  • 嗯,好的。在 C 中,我总是会溢出,而且我对 C++ 还是很陌生。谢谢
  • @cprogcr 同样,这也是 C 语言中未定义的行为。编译器优化可以利用它并将(x < x + 1) 之类的表达式转换为true,即使如果有符号数字环绕,这将不是真的。
【解决方案3】:

@Pubby 我不知道 C/C++ 标准是否定义了有符号整数溢出时的行为,但 gcc 似乎并不总是将 (x (int)x

以下代码产生输出:1 0 0 0 (32bit Linux + gcc)

signed char c1, c2; 
signed int i1, i2; 

c1 = 127;
c2 = c1 + 1;

i1 = 2147483647;
i2 = i1 + 1;

printf("%d %d\n", c1 < c1 + 1, c1 < c2);
printf("%d %d\n", i1 < i1 + 1, i1 < i2);

【讨论】:

  • 你说得对,GCC 并不总是做这种优化,但我不喜欢你测试它的方式。 GCC 的不断传播几乎肯定会影响您的结果。试着把它放在一个函数中,像这样:coliru.stacked-crooked.com/a/0528ff7d7e6a79f2
【解决方案4】:

一个char一般是8 bitsbyte,因此可以容纳2^8不同的值。如果是unsigned,从0255,否则,当signed-128127

【讨论】:

    【解决方案5】:

    您会看到coutprintf 之间的区别。当您输出带有cout 的字符时,您不会得到数字表示,而是得到一个字符。在这种情况下,字符是NUL,它不会出现在屏幕上。

    查看http://ideone.com/7n6Lqc的示例

    【讨论】:

      【解决方案6】:

      unsigned char 的值(通常是迂腐的)是从 0 到 255。有 256 个值,1 个字节可以容纳。

      如果你得到溢出(通常)值使用模 256,作为其他整数类型模 MAX + 1

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-29
        • 1970-01-01
        • 2012-10-03
        • 2010-09-06
        • 1970-01-01
        • 2011-02-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多