是左移C++03中未定义的有符号整数行为
Is left-shifting a signed integer undefined behavior in C++03?
根据C++03,5.8/2,左移定义如下:
E1<lt;E2是E1(解释为比特模式)左移位的E2比特位置;空出的比特被零填充。如果E1具有无符号类型,则结果的值为E1乘以数量2的幂E2,如果E1具有类型unsigned long,则减模ULONG_MAX+1,否则为UINT_MAX+1。
这里困扰我的是,显式地提到了无符号类型,而完全忽略了有符号类型。将其与定义右移的5.8/3进行比较:
E1>>E2的值是E1右移E2位的位置。如果E1具有无符号类型,或者如果E1具有有符号类型和非负值,则结果的值是E1的商除以量2的整数部分,该量是E2的幂。如果E1具有带符号类型和负值,则生成的值是实现定义的。
在5.8/3中,有符号和无符号都被明确提及,甚至有符号持有非负值和有符号持有负值也被单独提及。
AFAIK当某些东西在C++标准中没有明确定义时,行为是未定义的。我也看到过这个问题,但它关注的是C和C++之间的差异,似乎没有一个每个人都会同意的答案。
左移是C++03中定义的有符号整数吗?
5.8/2表示,它将其解释为一个位模式,只有当您的实现出于某种原因没有使用2的补码,或者编译器再次猜测您(他们没有)时,它才与实现相关。C++11更明确,但也表达了同样的观点。
有符号整数使用2的补码。基本上,如果你将一个有符号整数位移1,如果它是正的并且低于2^(位-2),它将像无符号一样工作。如果它高于该值但为正,则会创建一个与原始值无关的奇怪负数。如果一开始是负数,你可能会得到一个负数,也可能是一个正数。
例如,如果我们有一个表示-1:的8位有符号整数
11111111 // -1
如果我们离开轮班,我们最终会得到
11111110 // -2
然而,假设我们有-120
10001000 // -120
我们最终会得到
00010000 // 16
显然这是不对的!
继续,使用数字65:
01000001 // 65
向左移动,这将变成:
10000001 // -127
相当于-127。
然而,数字16:
00010000 // 16
向左移动是
00100000 // 32
正如你所看到的,它"有时有效,有时无效",但如果你的数字低于2^(bits-2),它通常有效,如果它高于-(2^(bit s-2)),它有时无效。也就是说,向左移动1。要左移2,再减去一位。等等。
我想补充一下,规则在C++11中发生了变化。
在C++11中,负数的有符号左移总是未定义的行为,即使底层机器为范围内的值定义了它。它不是定义的实现,而是未定义的。这意味着,如果你这样做,编译器可以自由地做任何它想做的事情,包括意外地删除你的一堆代码。这与负数的有符号右移形成对比,后者是实现定义的,这意味着其结果取决于机器类型。
Clang的-fsanitize=undefined
模式捕捉向左移动负数的尝试。
- 检查TCHAR数组输入是否为带符号整数C++
- 如何打印boost多精度128位无符号整数
- C++模板函数,用于比较任何无符号整数和有符号整数
- 为什么乘以常量有符号整数分数没有优化?
- 在线程中读取无符号整数时,c++ 位是否以原子方式切换?
- FlatBuffers/Protobuf 中是否有支持任意 24 位有符号整数定义的可移植二进制序列化架构?
- C++11 标准是否保证零值有符号整数的一元减号为零?
- Constexpr 可变参数模板,用于对无符号整数进行重新排序
- 为什么 Clang 和 GCC 中两个无符号整数之和的结果类型不同
- 为什么对无符号字符进行算术运算会将它们提升为有符号整数
- 从 std::string 转换为 const 无符号整数
- 迭代器和无符号整数的重载 + 运算符
- C++,概念不适用于无符号整数作为结果类型?
- 在C++中,将无符号整数转换为八进制表示,反之亦然的最佳方法是什么
- 原子式清除无符号整数的最低非零位
- 什么是 16 字节有符号整数数据类型?
- 计算机使用什么方法添加无符号整数
- 运行时错误:有符号整数溢出:964632435 * 10 无法在类型 'int' 中表示
- boost::任何带有结构体和无符号整数
- 添加有符号和无符号整数