整理C++常用整数运算的所有细节
2017-05-06 16:38
225 查看
前段时间写我的安全整数类checked,顺便就通读了标准中关于整数运算的部分,还发现了不少坑,以及自己没有了解的细节,这里就总结一下。要注意的是,C和C++在这部分的逻辑不相同
bool会被转换为int,其中false=0,true=1
bit field和enum不讨论
所以这里要注意,整数类型提升不保证符号性不变,但是一定不会发生溢出
用C++代码获取提升后的类型可以利用decltype和单目+运算符
对于三目运算符,会对冒号两侧的操作数进行如上转换,逻辑不变
移位运算符不进行本转换
这个转换是造成整数表示溢出的罪魁祸首
这个转换的结果类型可以用标准库设施 std::common_type 获取
有符号数运算溢出,是UB
移位的右操作数是负数,是UB
移位数>=左操作数的bit数,是UB
有符号数左移,修改了符号位,是UB
特别的,C++14中规定有符号左移是以相同二进制表示的无符号数进行左移,然后再转换回有符号,转换的行为依然是实现定义的
有符号数右移,行为是实现定义的,用人话说就是,标准没有规定有符号数右移一定是符号扩展(但是目前所有的编译器和CPU实现都是符号扩展)
有符号数进行位运算,修改了符号位,不算UB
A @= B等同于A = A @ B,遵循上面提到的类型提升过程
++和--的运算过程等同于+=1和-=1,遵循上面提到的类型提升过程
bool++和++bool的结果是true,这个C++17删掉了
第一步,单操作数的类型提升(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删掉了
相关文章推荐
- 整理 C++ 中 Allocator 的(几乎)所有细节 1
- python3基础之整数常用的方法整理
- 算法题: 求一个整数数组中,通过元素加减运算得到指定结果的所有运算过程. 例如【5,4,6,7,1】= 9 ?
- C#调用C++的DLL搜集整理的所有数据类型转换方式
- C#调用C++的DLL搜集整理的所有数据类型转换方式
- js常用事件整理—兼容所有浏览器
- c++基础复习:c++模板编程常用用法整理
- C++常用细节
- C#调用C++的DLL搜集整理的所有数据类型转换方式
- C++常用的函数,好的博客文章整理,集锦
- 收藏 不显示删除回复显示所有回复显示星级回复显示得分回复 汇编常用知识整理
- C++ map的常用的使用方法整理
- Latex所有常用数学符号整理
- c/c++整理--位运算与嵌入式编程(1)
- C#调用C++的DLL搜集整理的所有数据类型转换方式
- C++常用技巧一(整理收集)
- CSDN爬虫(五)——CSDN用户(所有)爬取+常用爬虫正则整理
- C++小细节(不定期整理 )
- C++:求一个整数的所有因子
- C/C++实现"输出100以内能被3整除且个位数为6的所有整数"