c - 将有符号转换为无符号,反之亦然,同时扩大字节数
问题描述
uint32_t a = -1; // 11111111111111111111111111111111
int64_t b = (int64_t) a; // 0000000000000000000000000000000011111111111111111111111111111111
int32_t c = -1; // 11111111111111111111111111111111
int64_t d = (int64_t) c; // 1111111111111111111111111111111111111111111111111111111111111111
从上面的观察来看,似乎只有原始值很sign
重要。即,如果原始的 32 位数字是无符号的,则将其转换为 64 位值将添加0's
到其左侧,而不管目标值是有符号还是无符号,并且;
如果原始 32 位数字是有符号且为负数,则将其转换为 64 位值将添加1's
到其左侧,而不管目标值是有符号还是无符号。
上述说法正确吗?
解决方案
正确,是源操作数决定了这一点。
uint32_t a = -1;
int64_t b = (int64_t) a;
这里没有符号扩展,因为源值是unsigned uint32_t
。符号扩展的基本思想是确保更广泛的变量具有相同的值(包括符号)。来自无符号整数类型,该值始终为正。下面的标准片段涵盖了这一点/1
。
负号扩展(从某种意义上说,二进制补码值的最高 1 位被复制到更宽类型(a)中的所有高位)仅在有符号类型的宽度扩展时发生,因为只有有符号类型可以消极的。
如果原始 32 位数字是有符号且为负数,则将其转换为 64 位值将在其左侧添加 1,无论目标值是有符号还是无符号。
下面的标准片段涵盖了这一点/2
。在扩展位时您仍然必须保持值的符号,但是将负值(假设源为负)推入无符号变量将简单地以数学方式将值添加MAX_VAL + 1
到值中,直到它在目标类型的范围内(在实际上,对于二进制补码,没有添加,它只是以不同的方式解释相同的位模式)。
这两种情况都包含在标准中,在这种情况下C11 6.3.1.3 Signed and unsigned integers /1
和/2
:
1/ 当一个整数类型的值转换为除 以外的其他整数类型
_Bool
时,如果该值可以用新的类型表示,则保持不变。2/ 否则,如果新类型是无符号的,则在新类型可以表示的最大值的基础上重复加减1,直到值在新类型的范围内。
3/ 否则,新类型是有符号的,值不能在其中表示;结果是实现定义的,或者引发了实现定义的信号。
请注意,上述前两点涵盖了您的扩大转换。我已经包含了完成的第三点,因为它涵盖了从uint32_t
到 的转换int32_t
,或者unsigned int
到long
它们具有相同宽度的位置(它们都有最小范围,但没有要求unsigned int
比 更“薄” long
)。
(a)这可能在一个的补码或符号大小表示中有所不同,但由于它们正在被删除,所以没有人真正关心那么多。
看:
- http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r1.html(WG21,C++);和
- http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2218.htm (WG14, C)
了解更多详情。
在任何情况下,固定宽度类型都是二进制补码,因此您不必担心示例代码的这一方面。
推荐阅读
- python - Python:使用查询字符串参数请求GET方法登录不确定是否成功
- powershell - 为什么 import-module 或点源文件在 powershell 脚本中不起作用?
- windows - 让自定义图标显示在“打开方式...”对话框中
- javascript - Wix Velo — 如何使用对象数组
- python - 销毁后的 Tkinter 包
- c# - 基于导航属性的 Entity Framework Core 计算字段为空。为什么?
- excel - EXCEL VBA 锁定列问题
- twitter-bootstrap - 为什么我的引导自定义文件类没有像示例那样显示
- javascript - 使用文件而不是迭代数据
- python - 如何在熊猫中选择NaN前后的行?