C是整数数学等价于无符号数学吗



那么,我可以将值强制转换为无符号值,执行运算并强制转换,得到相同的结果吗?我想这样做是因为无符号整数可能溢出,而有符号整数不能溢出。

无符号整数算术在C术语中不会溢出,因为它被定义为包装模2N,其中N是根据C 2018 6.2.5 9:运算的无符号类型中的位数

…涉及无符号操作数的计算永远不会溢出,因为无法由结果的无符号整数类型表示的结果会以比结果类型所能表示的最大值大一的数字为模进行减少。

对于其他类型,如果发生溢出,则行为不由C标准定义,根据6.5 5:

如果在表达式求值过程中出现异常条件(即,如果结果未在数学上定义或不在其类型的可表示值范围内(,则行为未定义。请注意,不仅结果是未定义的;程序的整个行为是未定义的。它可能会给出你意想不到的结果,可能会陷阱,也可能会执行与你预期完全不同的代码。

关于您的问题:

那么,我可以将值强制转换为无符号值,执行运算并强制转换,得到相同的结果吗?

我们有两个问题。首先,考虑给定int a, b;a + b。如果a + b溢出,则行为不由C标准定义。因此,我们不能说转换为unsigned、相加和转换回int是否会产生相同的结果,因为a + b没有定义的结果。

其次,根据C 6.3.1.3,转换回部分由实现定义。考虑int c = (unsigned) a + (unsigned) b;,它隐式地将unsigned和转换为int以存储在c中。第1段告诉我们,如果和的值在int中是可表示的,那么它就是转换的结果。但第3段告诉我们,如果值不能在int:中表示,会发生什么

否则,将对新类型进行签名,并且无法在其中表示值;要么结果是实现定义的,要么产生实现定义的信号。

GCC将结果定义为包装模2N的结果。因此,对于int c = (unsigned) a + (unsigned) b;,GCC将产生与int c = a + b;相同的结果,如果a + b封装模2N。然而,GCC并不保证后者。在优化时,GCC预计不会发生溢出,这可能会导致它消除程序允许发生溢出的任何代码分支。(GCC在处理溢流方面可能有一些选择。(

此外,即使有符号算术和无符号算术都进行了包装,使用无符号值执行运算并进行转换在数学上也不会产生与使用有符号值执行操作相同的结果。例如,考虑-3/2int的结果为−1。但是,如果将-3转换为32位无符号,则结果值为232−3,然后(int) ((unsigned) -3 / (unsigned) 2)为2−31−2=2147483646。

最新更新