签名的整数变量在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
, ,看起来好像该值已经包裹着。