无符号vs有符号范围保证

时间:2012-07-07 03:32:56

标签: c++ c

我花了一些时间仔细阅读标准参考文献,但我无法找到以下答案:

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

我得到的最接近的是来自C99标准的 6.2.6.2 部分(C ++的措辞对我来说更加神秘,我认为它们相当于此):

  

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

因此,在假设的4位有符号/无符号整数类型中,是否有任何阻止无符号类型具有1个填充位和3个值位的东西,以及带有3个值位和1个符号位的带符号类型?在这种情况下,无符号的范围将是[0,7],对于有符号,它将是[-8,7](假设是2的补码)。

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

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

2 个答案:

答案 0 :(得分:7)

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

我将讨论类型intunsigned int;这同样适用于任何对应的有符号和无符号类型(charunsigned 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个值位,一个普通的二进制补码表示,unsigned int有31个值位和一个填充位。具有该填充位集的unsigned int表示可以是陷阱表示,也可以是未填充填充位的值的额外表示。

这可能适用于支持二进制补码有符号算术的机器,但对无符号算术的支持很差。

鉴于这些特征,-INT_MIN(数学值)超出unsigned int的范围。

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

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

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

到您的源代码,因此只有在您可以执行所需操作时才会编译。 (当然,您应该考虑比"Nope"更好的错误消息。)

答案 1 :(得分:3)

你明白了。在C ++ 11中,措辞更清晰。 §3.9.1/ 3:

  

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

但是,两种相应类型之间的连接究竟有什么意义呢?它们的大小相同,但如果只有局部变量则无关紧要。

  

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

您需要处理机器支持的任何数值范围。而不是转换为无符号对应物,转换为无符号类型就足够了:如果需要,可以使用大于对应的类型。如果不存在足够大的类型,则机器可能无法执行您想要的操作。