我在c规格中读了一些无符号变量(特别是 未签名的短 int)执行一些所谓的 环绕 在整数溢出上,尽管我在签名变量上找不到任何东西 不确定的行为.

我的教授告诉我,他们的价值观也被包裹起来(也许他只是意思是GCC)。我以为这些碎片被截断了,我留下的碎屑给了我一些奇怪的价值!

周围的包裹是,它与仅截断位有何不同。

有帮助吗?

解决方案

签名的整数变量在C语言中没有包裹的行为。算术计算期间签名的整数溢出会产生 不确定的行为. 。请注意,您提到的GCC编译器以实施而闻名 严格的溢出语义 在优化中,这意味着它利用了这种不确定的行为情况提供的自由:GCC编译器假设签名的整数价值永远不会包裹。这意味着GCC实际上恰好是您的编译器之一 不能 依靠签名整数类型的环绕行为。

例如,GCC编译器可以假定用于变量 int i 以下条件

if (i > 0 && i + 1 > 0)

相当于仅

if (i > 0)

这正是 严格的溢出语义 方法。

未签名的整数类型实现模型算术。 Modulo相等 2^N 在哪里 N 是类型的值表示中的位数。因此,未签名的整数类型确实确实在溢出上包裹着。

但是,C语言永远不会在域中执行算术计算 int/unsigned int. 。类型 unsigned short int 您在问题中提到的通常会晋升为类型 int 在任何计算开始之前的表达式中(假设 unsigned short 适合 int)。这意味着1)与 unsigned short int 将在 int, ,随着溢出的发生 int 溢出,2)在此类计算过程中溢出将导致不确定的行为,而不是包裹行为。

例如,此代码会产生包裹

unsigned i = USHRT_MAX;
i *= INT_MAX; /* <- unsigned arithmetic, overflows, wraps around */

同时此代码

unsigned short i = USHRT_MAX;
i *= INT_MAX; /* <- signed arithmetic, overflows, produces undefined behavior */

导致不确定的行为。

如果不 int 溢出发生,结果转换回 unsigned short int 类型,Modulo再次减少了 2^N, ,看起来好像该值已经包裹着。

其他提示

想象一下,您的数据类型只有3位。这使您可以表示8个不同的值,从0到7。如果添加1到7,则将“缠绕”回到0,因为您没有足够的位来表示值8(1000)。

对于未签名类型,此行为定义明确。这是 不是 对于签名类型的定义明确,因为有多种表示签名值的方法,并且溢出的结果将根据该方法进行不同的解释。

标志尺度:最上位表示标志; 0为阳性,为1。如果我的类型再次宽三位,那么我可以表示签名的值如下:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -0
101  = -1
110  = -2
111  = -3

由于符号要占用一位,因此我只有两个位来编码一个从0到3的值。如果我添加1到3,则结果是-0。是的,有两个表示为0,一个是正面的,一个是负面的。您不会经常遇到符号刻板表示。

一个人的组合:负值是正值的皮层。同样,使用三位类型:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -3
101  = -2
110  = -1 
111  = -0

我有三个位来编码我的值,但范围是[-3,3]。如果我添加1到3,结果我会溢出-3。这与上面的符号结果不同。同样,使用此方法有两个针对0的编码。

两个组合:负值是正值的位倒数,加1。在三位系统中:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -4
101  = -3
110  = -2
111  = -1

如果我添加1到3,则我将溢出-4,这与前两种方法不同。请注意,我们的值范围稍大[-4,3],只有一个表示0。

两者的补充可能是表示签名值的最常见方法,但它不是唯一的补充方法,因此C标准无法保证当您溢出签名的整数类型时会发生什么。所以它留下了行为 不明确的 因此,编译器不必处理解释多个表示。

不确定的行为 当签名的整数类型可以表示为标志和大小,一个人的补充或两者的补充时,来自早期便携性问题。

如今,所有架构都代表整数是两者的补充。但是要小心:由于您的编译器是正确的,因此可以假设您不会运行未定义的行为,因此在优化时可能会遇到奇怪的错误。

在一个签名的8位整数中,周围的包裹的直观定义看起来像是从+127到-128-在两个补充二进制中:0111111(127)和1000000(-128)。如您所见,这是增加二进制数据的自然进步 - 不考虑它代表整数,签名或未签名。反直观地,实际的溢出发生在未签名整数环绕感中的-1(11111111)到0(00000000)时。

这不会回答更深层的问题,即当签名整数溢出时,正确的行为是什么,因为没有根据标准存在“正确”的行为。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top