首页 文章

无符号vs有符号范围保证

提问于
浏览
9

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

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

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

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

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

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

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

2 回答

  • 3

    对于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个值位,一个普通的2位补码表示, unsigned int 有31个值位和一个填充位 . 具有该填充位集的 unsigned int 表示可以是陷阱表示,或者是未填充填充位的值的额外表示 .

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

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

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

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

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

    到你的来源,所以只有你能做你想做的事情才会编译 . (当然,你应该想到比 "Nope" 更好的错误信息 . )

  • 7

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

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

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

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

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

相关问题