9

我花了一些时间研究标准参考资料,但我无法找到以下问题的答案:

  • C/C++ 标准是否在技术上保证,给定有符号整数类型 S 及其无符号对应物 U,每个可能的 S 的绝对值始终小于或等于 U 的最大值?

我得到的最接近的是来自 C99 标准的第6.2.6.2节(C++ 的措辞对我来说更神秘,我认为它们在这方面是等价的):

对于有符号整数类型,对象表示的位应分为三组:值位、填充位和符号位。(...) 作为值位的每个位应与对应无符号类型的对象表示中的相同位具有相同的值(如果有符号类型中有 M 个值位,无符号类型中有 N 个值位,则 M≤ N)。

那么,在假设的 4 位有符号/无符号整数类型中,是否有任何东西阻止无符号类型具有 1 个填充位和 3 个值位,以及有符号类型具有 3 个值位和 1 个符号位?在这种情况下,无符号的范围是 [0,7],而有符号的范围是 [-8,7](假设二进制补码)。

万一有人好奇,我现在依靠一种技术来提取负整数的绝对值,该技术包括首先转换为无符号对应物,然后应用一元减运算符(例如 - 3 通过强制转换变为 4,然后通过一元减号变为 3)。这将在上面的 -8 示例中中断,无法以无符号类型表示。

编辑:感谢 Keith 和 Potatoswatter 下面的回复。现在,我的最后一点疑问是标准措辞中“子范围”的含义。如果这意味着严格的“小于”包含,那么我上面的示例和 Keith 下面的示例不符合标准。如果子范围可能是无符号的整个范围,那么它们就是。

4

2 回答 2

7

对于 C,答案是否定的,没有这样的保证。

我将讨论类型intunsigned int;这同样适用于任何对应的有符号和无符号类型对(除了charand unsigned char,它们都不能有填充位)。

在您引用的部分中,该标准隐含地保证UINT_MAX >= INT_MAX,这意味着每个非负值int都可以表示为unsigned int

但以下是完全合法的(我将用它**来表示幂):

CHAR_BIT == 8
sizeof (int) == 4
sizeof (unsigned int) == 4
INT_MIN  = -2**31
INT_MAX  = +2**31-1
UINT_MAX = +2**31-1

这意味着它int有 1 个符号位(它必须)和 31 个值位,一个普通的 2 的补码表示,并且unsigned int有 31 个值位和一个填充位。 unsigned int设置了该填充位的表示可能是陷阱表示,或者是未设置填充位的值的额外表示。

这可能适用于支持 2 补码有符号算术但对无符号算术支持较差的机器。

鉴于这些特征,-INT_MIN(数学值)在 范围之外unsigned int

另一方面,我严重怀疑是否存在这样的现代系统。填充位是标准允许的,但非常罕见,我不希望它们变得更常见。

您可以考虑添加如下内容:

#if -INT_MIN > UINT_MAX
#error "Nope"
#endif

到你的源代码,所以只有当你能做你想做的事情时它才会编译。(当然,您应该考虑比 更好的错误消息"Nope"。)

于 2012-07-07T04:08:57.087 回答
3

你说对了。在 C++11 中,措辞更加清晰。§3.9.1/3:

有符号整数类型的非负值范围是对应无符号整数类型的子范围,每个对应的有符号/无符号类型的值表示应相同。

但是,这两种对应类型之间的联系究竟有什么意义呢?它们的大小相同,但是如果您只有局部变量,那就没关系了。

万一有人好奇,我现在依靠一种技术来提取负整数的绝对值,该技术包括首先转换为无符号对应物,然后应用一元减运算符(例如 - 3 通过强制转换变为 4,然后通过一元减号变为 3)。这将在上面的 -8 示例中中断,无法以无符号类型表示。

您需要处理机器支持的任何数字范围。与其强制转换为无符号对应物,不如强制转换为任何无符号类型就足够了:如果需要,比对应物大一个。如果没有足够大的类型存在,那么机器可能无法执行您想要的操作。

于 2012-07-07T03:47:31.293 回答