zoukankan      html  css  js  c++  java
  • 整理C++常用整数运算的所有细节

    前段时间写我的安全整数类checked,顺便就通读了标准中关于整数运算的部分,还发现了不少坑,以及自己没有了解的细节,这里就总结一下。要注意的是,C和C++在这部分的逻辑不相同

    第一步,单操作数的类型提升(integral promotion)

    • 对于C++中的所有字符类型,char,signed char,unsigned char,wchar_t,char16_t,char32_t,和所有小于等于int的类型,比如short,unsigned short,他们会被提升为对应的整数类型,这个对应的整数类型的选取逻辑是这样的:如果源类型的值域包含于int,那么就选择int,否则依次尝试unsigned int,long,unsigned long,long long,unsigned long long。
    • bool会被转换为int,其中false=0,true=1
    • bit field和enum不讨论

    所以这里要注意,整数类型提升不保证符号性不变,但是一定不会发生溢出

    用C++代码获取提升后的类型可以利用decltype和单目+运算符

    template<class T>
    using integral_promoted_type_t = decltype(+T{});
    

    第二步,双操作数的类型提升(usual arithmetic conversion)

    • 对于二元运算,经过了上面所述的类型提升,如果运算符左右边的类型仍不相同,那么会进行进一步的提升,使得两个操作数的类型相同,逻辑上基本就是小的类型向大的类型转换,标准引入了 conversion rank 的概念,也是为了说清楚什么是“小的类型”和“大的类型”。
    • 对于三目运算符,会对冒号两侧的操作数进行如上转换,逻辑不变
    • 移位运算符不进行本转换

    这个转换是造成整数表示溢出的罪魁祸首

    这个转换的结果类型可以用标准库设施 std::common_type 获取

    第三步,正式进行数学运算

    走过以上的类型提升步骤之后,左右操作数的类型都相同了,此时可以进行数学运算。

    • 有符号数运算溢出,是UB
    • 移位的右操作数是负数,是UB
    • 移位数>=左操作数的bit数,是UB
    • 有符号数左移,修改了符号位,是UB
    • 特别的,C++14中规定有符号左移是以相同二进制表示的无符号数进行左移,然后再转换回有符号,转换的行为依然是实现定义的
    • 有符号数右移,行为是实现定义的,用人话说就是,标准没有规定有符号数右移一定是符号扩展(但是目前所有的编译器和CPU实现都是符号扩展)
    • 有符号数进行位运算,修改了符号位,不算UB
    • A @= B等同于A = A @ B,遵循上面提到的类型提升过程
    • ++和--的运算过程等同于+=1和-=1,遵循上面提到的类型提升过程
    • bool++和++bool的结果是true,这个C++17删掉了
  • 相关阅读:
    quota磁盘配额
    lvm管理
    快照
    分区工具
    课下测试03!03!03!题目截图及解析(不完全正确)第四周--信息安全系统设计基础
    2017-2018-1 20155307《信息安全技术李冬冬》实验二——Windows口令破解
    2017-2018-1 20155301 20155307 20155339 《信息安全系统设计基础》 实验一 开发环境的熟悉
    2017-2018-1 20155307 《信息安全系统设计基础》第5周学习总结
    PGP的原理与使用
    2017-2018-1 20155307 《信息安全系统设计基础》第四周学习总结
  • 原文地址:https://www.cnblogs.com/pointer-smq/p/6817227.html
Copyright © 2011-2022 走看看