是对定义良好的有符号整型进行位操作的结果
Are the result of bitwise operations on signed integral types well-defined?
考虑以下代码:
using integer = int; // or any other fundamental integral type
using unsigned_integer = typename std::make_unsigned<integer>::type;
constexpr integer bits = std::numeric_limits<unsigned_integer>::digits;
integer value = -42; // or any value
integer mask = static_cast<integer>(1)<<static_cast<integer>(bits-1);
bool result_and = value & mask;
bool result_or = value | mask;
bool result_xor = value ^ mask;
我想知道这些操作是如何根据标准定义的。我能保证在所有架构上得到相同的结果吗?我确定在所有的体系结构上对符号位进行操作这个符号位是0
表示正数1
表示负数?
位和、位或和位异的结果目前在标准中没有明确规定,特别是术语位从未定义。我们有缺陷报告1857:关于比特的附加问题,它涵盖了这个问题,并说:
5.11 [exp .bit.and]中按位操作的规范,5.12 [expr。Xor],和5.13 [expr。Or]在描述操作时使用未定义的术语"按位",而不指定它是否是视图中的值或对象表示。
解决这个问题的部分方法可能是将" bit "(在c++中目前没有定义)定义为给定2的幂的值。
,分辨率为:
CWG决定重新制定操作描述它们自己避免引用比特,分裂出较大的关于定义"位"之类的问题,1943年再说吧考虑。
这导致了一个合并的缺陷报告1943:"bit"的未指定含义。
左移有符号类型的结果将取决于底层表示。我们可以从缺陷报告1457中看到这一点:左移中的未定义行为使得左移到符号位并说:
当前的措辞5.8 [expr。第2段使它没有定义创建给定类型的最大负整数的行为左移a(有符号)1到符号位,即使这不是不寻常的完成和工作正确的大多数(twos-complement)架构:
…如果E1具有带符号类型且非负值,且E1在结果类型中可表示,则该值为结果值;否则,行为是未定义的。
因此,该技术不能用于常量表达式。这会破坏大量的代码。
注意语句的重点在大多数情况下是正确的 (twos-complement)架构。因此,它依赖于底层表示,例如two -complement。
关于左移和右移操作符,来自c++标准第5.8节:
如果右操作数为负或大于负,则该行为未定义小于或等于提升后左操作数的位长度
左移运算符E1 <<当满足以下所有条件时,E2将导致未定义行为:
- 左操作数为有符号类型
- 左操作数要么为负值,要么为非负值,使得E1 × 2^E2在结果类型中不可表示。
对于右移操作符E1>> E2,如果左操作数为带符号类型且为负值,则其行为与实现相关。
对于所有整型都定义了位与、异或和或操作符。这分别在第5.11、5.12和5.13节中指定。
但是,请注意,有符号整数值的表示可以是2的补数、1的补数或有符号幅度。大多数编译器使用Two的补码表示。包括gcc、vc++、icl和Clang。
操作符&
, |
和^
是按位的,并且处理单个位,因此它们将完全按照您所写的操作:应用mask
。
左移<<
操作符有点棘手。如果将负值移位,或者将1移位到符号位或其他位置,将导致未定义行为。
static_cast<integer>(1)<<static_cast<integer>(bits-1);
似乎你把1
移到那里的符号位位置,这是未定义的行为。
- C 字符串返回字符串的整数/双精度/长整型值
- 是什么导致了这种使用三进制而不是短整型的有符号int到无符号int转换
- 无法在 Arduino 中uint8_t数组转换为无符号长整型数组
- JNI 日期值转换问题,在C++中获取不同的长整型值
- 将长整型值打印为带有前导零的十六进制
- 为什么在传递长整型时调用具有两个双精度类型的参数的重载函数?
- 将整型常量映射到类型
- 将元组和整型实例合并到引用元组中
- 提升不良词法强制转换:将字符串转换为无符号长整型时,无法将源类型值解释为目标
- 为什么C++不允许两个同名的函数/类模板,区别仅在于非类型模板参数(整型)的类型?
- 将最小值整数转换为无符号长整型
- 如何将小端格式的QByteArray转换为无符号长整型
- 直接初始化无符号短整型的标准行为
- 无符号长整型和无符号 int 之间有什么区别,这 2 种类型应该如何在 c# 中封送?
- 无符号和有符号短整型的位宽
- 将整型转换为浮点型时检测溢出
- 环礁和(长整型)的区别?
- 为什么允许将整型、枚举和指向成员的指针类型reinterpret_cast到自身?
- 用有符号长整型结果减去无符号长整型
- 是对定义良好的有符号整型进行位操作的结果