大小应该使用有符号整数还是无符号整数
Should signed or unsigned integers be used for sizes?
标准库vector::size()
给出一个size_t
,一个无符号数。在CppCon的一次演讲中,我听到有人(是Chandler Carruth吗?)说这很不幸,它应该使用有符号整数。
背景是溢出不是为有符号整数定义的,因此编译器有更多的余地。在一次演讲中,Carruth展示了作为bzip2中for
循环索引的uint8_t
如何在x86上创建比int8_t
多得多的机器指令,因为它必须用掩码和移位显式地模拟溢出。
在我现在处理的代码中,有一些大小是严格正的。这些被表示为CCD_ 6。这看起来不错,因为这表明他们不可能是消极的。另一方面,不需要定义的模运算,所以只要有符号整数足够大(我们转到200),无符号整数就会为我们想要的运算提供错误的接口。
在代码中的某个点上,存在从0到该大小的循环。然后减去循环索引,取绝对值。
当我用更现代的GCC 7编译它时,它无法解决std::abs
的适当过载问题,因为size_t - size_t
显然给出了令人震惊的值。我已将代码更改为在循环索引中使用int
:
for (int t1 = 0; t1 < Lt; t1++) {
for (int t2 = 0; t2 < Lt; t2++) {
现在abs(t1 - t2)
运行良好。但是比较t1 < Lt
给出了一个警告,因为它是有符号和无符号数字之间的比较。
什么是正确的方法?
- 对任何非负的值使用无符号整数,然后在需要执行子运算时使用
static_cast<int>()
- 循环索引使用有符号整数,容器大小使用无符号整数。然后在比较中使用
static_cast<int>
- 只需在任何地方使用有符号整数。当其他库返回无符号整数时,只需在那里使用
static_cast<int>
即可满足警告
"在一次演讲中,Carruth展示了uint8_t作为bzip2中的for循环索引如何在x86上创建比int8_t多得多的机器指令,因为它必须用掩码和移位显式地模拟溢出。">
如果可以使用任意一种类型,则for范围必须限制为[0, 127]
。那么,只需使用int
作为索引类型。根据定义,它是基本数学运算的自然类型,通常很好地映射到CPU寄存器。
使用为最小存储量优化的类型不会产生最快的数学结果。这并不奇怪。基于这种有缺陷的设置,你无法得出关于已签名与未签名的结论。
"size_t
-size_t
给出不明确的值">
它没有,但它确实使用了模运算。size_t(1)-size_t(2)==size_t(-1)
,但size_t(-1)
是最大可能的值。这直接源于模块数学的定义:x-1 < x
,除非x-1
由于x==0
而环绕。(或等效x+1>x
,x+1==0
除外)
因此调用abs(size_t(x))
也是毫无意义的,因为每个size_t
值都是正的。将有符号整数与size_t
进行比较同样充满了意想不到的后果。显式类型转换很好,因为它们可以清楚地显示结果。
但是,并没有一个通用的解决方案来自动确定应该应用哪种类型。如果可以发明一个机械规则,我们就可以把这个规则留给编译器。我们没有,因为我们做不到。作为一名程序员,你必须用数字来考虑每一种情况。
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 检查TCHAR数组输入是否为带符号整数C++
- 如何打印boost多精度128位无符号整数
- C++模板函数,用于比较任何无符号整数和有符号整数
- 在数字之间插入 + 或 - 符号以使其等于整数
- 为什么:不同符号的整数比较只是偶尔发生?
- 将超出范围的整数分配给有符号字符类型
- 为什么乘以常量有符号整数分数没有优化?
- 如何解决隐式转换丢失整数精度:'size_t'(又名"无符号长")到'int'警告?
- 在线程中读取无符号整数时,c++ 位是否以原子方式切换?
- FlatBuffers/Protobuf 中是否有支持任意 24 位有符号整数定义的可移植二进制序列化架构?
- C++11 标准是否保证零值有符号整数的一元减号为零?
- 整数类型应该显式转换(例如"int"到"无符号")还是只会增加混乱?
- Constexpr 可变参数模板,用于对无符号整数进行重新排序
- AVX2 整数乘以有符号 8 位元素,产生有符号 16 位结果?
- 为什么 Clang 和 GCC 中两个无符号整数之和的结果类型不同
- 使用192/256位整数求和无符号64位整数向量的点积的最快方法
- 为什么对无符号字符进行算术运算会将它们提升为有符号整数
- 从 std::string 转换为 const 无符号整数
- 矢量浮点到整数/符号转换