在C中包含有符号和无符号变量的解释?

我在C规范中读到了一点,无符号变量(特别是unsigned short int )在整数溢出上执行一些所谓的回绕,尽管除了我留下未定义的行为之外我找不到任何有符号的变量。 我的教授告诉我他们的价值观也被包围了。(也许他只是意味着gcc)我认为这些比特被截断了,我留下的位给了我一些奇怪的价值?! 那么,任何人都可以解释什么是环绕的,它与截断位有什么不同。

有符号整数变量在C语言中没有环绕行为。 算术计算期间的有符号整数溢出会产生未定义的行为 。 请注意,您提到的GCC编译器在优化中实现严格溢出语义是已知的,这意味着它利用了这种未定义行为情况提供的自由:GCC编译器假定有符号整数值永远不会回绕。 这意味着GCC实际上恰好是您不能依赖有符号整数类型的环绕行为的编译器之一。

例如,GCC编译器可以假设对于变量int i具有以下条件

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

相当于一个人

 if (i > 0) 

这正是严格溢出语义的含义。

无符号整数类型实现模运算。 模数等于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类型,则它再次被模2^N减少,这将看起来好像值已经被包围。

想象一下,你的数据类型只有3位宽。 这允许您表示从0到7的8个不同值。如果添加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)时发生实际溢出。

这没有回答更深层次的问题,即当有符号整数溢出时正确的行为是什么,因为根据标准没有“正确”的行为。