RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 725841
Accepted
wololo
wololo
Asked:2020-10-03 01:10:33 +0000 UTC2020-10-03 01:10:33 +0000 UTC 2020-10-03 01:10:33 +0000 UTC

在 C++ 中将一元减号应用于无符号值

  • 772

语言标准一再提到对无符号整数的运算是模执行的2^n,其中n是表示无符号整数值所涉及的位数。

让我们有这个代码:

    unsigned char a = 1;
    a = -a;

而且,让unsigned char八位,但int十六位。

我已经认为表达式-a要么立即转换为类型的值unsigned char,等于255; 要么a扩展为int,然后这个int接受一个值-1,最后-1转换为类型unsigned char等于的值255。然而,事实证明,该标准指定了一种特殊的、相当奇怪的方法来计算无符号值的一元减号。

这是该文件第 8.3.1/8 段的引述:

一元 - 运算符的操作数应具有算术或无范围枚举类型,结果是其操作数的否定。对整数或枚举操作数执行整数提升。无符号量的负数是通过从 中减去其值来计算的2^n,其中n是提升操作数中的位数。结果的类型是提升的操作数的类型。

如果我理解正确写的内容,那么-a上面示例中的表达式的值等于 value 2^n - 1,它n等于扩展操作数中的位数。那些。2^n - 1 == 2^16 - 1 == 65536 - 1 == 65535. 但是给定的值不能用 16 位表示int,这意味着尝试计算-a会导致未定义的行为。

问题是:一元减法可以像上面写的那样“起作用”吗?如果是这样,为什么标准会为无符号值定义这种奇怪的一元减法行为?


如果你这样写也很奇怪:

    unsigned char a = 1;
    a = 0 - a;

那么它似乎不会导致未定义的行为。因为它0是 type int,所以变量被a扩展为int,计算差值0-1,并且 type 的结果值被int安全地截断256为255。

c++
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    jfs
    2020-10-03T18:36:48Z2020-10-03T18:36:48Z

    关于 2 n的词仅适用于无符号类型(模算术max() + 1- 结果始终是定义的)。这些词不是指 int 类型。

    如果unsigned char一个类型的所有值都适合int(经常发生),那么(C++ n4659 §7.6.1):

    -(unsigned char)1 = (integer promotion, likely) = -(int)1 = (int)-1
    

    如果它们不适合,则:

    -(unsigned char)1 = (integer promotion, rare) = -(unsigned int)1 
        = (unsigned int)2**n-1 = (by definition) = (unsigned int)UINT_MAX
    

    其中n是值的位数(值位 - 可能与sizeof * CHAR_BIT是否有填充位不同 - C n1570 §6.2.6.2.1)。

    也就是说,-a 表达式的类型是 int 或 unsigned int。要分配回a您需要(可能是缩小转换)到无符号字符:

    (int)-1 = (UCHAR_MAX + 1) - 1 = (unsigned char)UCHAR_MAX
    

    或者:

    (unsigned int)UINT_MAX = UINT_MAX % (UCHAR_MAX + 1) = (unsigned char)UCHAR_MAX
    

    即在这种情况下总是获得该值 2 CHAR_BIT -1:

    a == std::numeric_limits<unsigned char>::max()
    
    • 3
  2. mr NAE
    2020-10-03T16:39:13Z2020-10-03T16:39:13Z

    让我们定义文档中的概念:

    第6.10条:

    prvalue是一个表达式,它的求值初始化一个对象或一个位域,或者计算一个运算符的操作数的值,由它出现的上下文指定

    7.6积分促销

    一个除bool、char16_t、char32_t或wchar_t以外的整数类型的prvalue,其整数转换秩(7.15)小于int的秩,如果int可以表示所有的值,则可以转换为int类型的prvalue源类型;否则,源纯右值可以转换为 unsigned int 类型的纯右值

    这一切的本质是在评估之后保留整个值范围,例如一元减号,泛型类型扩展int。此操作(提升的操作数)的必要性由上下文决定。

    在代码中

    unsigned char a = 10;
    unsigned char b = -a;
    

    泛化扩展可以省略,因为结果和它的存储位置都是一个字节,不需要额外的存储空间。这里N=8, 2^8=256, 256-10=246. 和这里

    int c = -a;
    

    存储结果的类型int,所以N=32,2^32-10=-10(在二进制补码中)。

    在8.3.1 一元运算符的第8 节中,声明该值N不应取自源类型,而应取自最终类型,特别是,它可以是通用的——所有这些都基于上下文。

    耙子非常接近:

    7.8 积分转换

    如果目标类型是有符号的,则如果它可以在目标类型中表示,则值不变;否则,该值是实现定义的。

    7.9 浮点转换

    浮点类型的纯右值可以转换为另一种浮点类型的纯右值。如果源值可以在目标类型中精确表示,则转换的结果就是该精确表示。如果源值介于两个相邻的目标值之间,则转换的结果是实现定义的选择这些值中的任何一个。否则,行为未定义

    因此,不应忽略有关尝试将有符号类型与无符号类型进行比较或隐式向下转换的编译器警告。

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5