【发布时间】:2017-11-14 10:33:37
【问题描述】:
标准库vector::size() 给出一个size_t,一个无符号数。在 CppCon 的一次演讲中,我听到有人(是 Chandler Carruth 吗?)说这很不幸,应该使用有符号整数。
背景是没有为有符号整数定义溢出,因此编译器有更多的余地。在一次谈话中,Carruth 展示了 uint8_t 作为 bzip2 中的 for 循环索引如何在 x86 上创建比 int8_t 更多的机器指令,因为它必须使用掩码和移位显式模拟溢出。
在我现在处理的代码中,某些大小是严格正数的。这些表示为size_t。这看起来不错,因为这表明它们不可能是负面的。另一方面,不需要定义的模运算,所以只要有符号整数足够大(我们去像 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>即可满足警告。
【问题讨论】:
-
如果你想要一个有符号的值,使用
ssize_t(注意额外的s)而不是int。 -
This 可能很有趣。
-
@Martin Ueding 所有这些考虑都没有意义。只是忽略他们。如果某些实体不能否定,则使用适当的无符号类型。
-
@VladfromMoscow:是的。然后执行
for (unsigned int i=0; i<size-1; i++) { }之类的错误 - 如果大小为 0,则循环 UINT_MAX 次。加上无符号整数禁用某些优化。这是一个糟糕的建议。 -
@juanchopanza:我想过这个,但没有写。不涉及模算术,在 Carruths 演讲之后,我认为无符号整数用于模算术而不是非负值。
标签: c++