C中的位移位无符号长整型 [英] Bit-shifting unsigned longs in C

查看:0
本文介绍了C中的位移位无符号长整型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我编写的一段代码中发现了一个错误,并已修复了它,但仍然无法解释发生了什么。归根结底是:

unsigned i = 1<<31;          // gives 21476483648 as expected
unsigned long l = 1<<31;     // gives 18446744071562067968 as not expected

我在这里注意到一个问题:Unsigned long and bit shifting其中完全相同的数字显示为意外的值,但在那里他使用的是有符号的字符,我相信这会导致符号扩展。我真的无论如何都不明白为什么我在这里得到了一个不正确的值。

我在Ubuntu 18.04上使用Clion,在我的系统上,aunsigned是32位,along是64位。

推荐答案

在此表达式中:

1<<31

1具有类型int。假设int是32位宽,这意味着您要将一位移入符号位。这样做是undefined behavior

C standard的6.5.7p4节记录了这一点:

e1;<;e2的结果是e1左移e2位位置;空出 位由零填充。如果e1具有无符号类型,则 结果的值是E1×2E2,模1比 结果类型中可表示的最大值。如果e1具有 带符号类型和非负值,以及E1×2E2可在 结果类型,则这是结果值;否则, 行为未定义。

但是,因为您使用的是使用GCC的Ubuntu,所以行为实际上是由实现定义的。gcc documentation说明:

按位运算符作用于值的表示形式,包括 符号位和值位,其中考虑符号位 紧接在最高值位的上方。签名>>作用于 带符号扩展的负数。

作为C语言的扩展,GCC没有使用给定的纬度 在C99和C11中,仅将签名的<<的某些方面视为 未定义。但是,-fsanitize=shift(和-fsanitize=undefined)将 诊断这类病例。他们也被诊断为常量 需要表达式。

所以在这种情况下,GCC直接致力于值的表示。这意味着1<<31具有类型int和表示0x80000000。此表示法的十进制表示值为‭-2147483648‬。

将此值分配给unsigned int时,将通过6.3.1.3p2:

一节中的规则进行转换
否则,如果新类型是无符号的,则值为 通过重复添加或减去 可以用新类型表示的最大值,直到 值在新类型的范围内。

由于32位unsigned int的"One More the Maximum Value"为‭42949672956,因此将int值-2147483648‬转换为unsigned int值‭42949672956-2147483648==2147483648‬。

1<<31分配给64位的unsigned long int时,"比最大值多1"为18446744073709551616,因此转换结果为18446744073709551616-2147483648==18446744071562067968,这是您获得的值。

若要获取正确的值,请使用UL后缀将值unsigned long

1UL<<31

这篇关于C中的位移位无符号长整型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆