我正在调查我的团队使用size_t
vs int
(或long
等)的标准。我看到的最大的缺点是,两个size_t对象的区别可能会导致问题(我不确定具体的问题 - 可能是某些东西没有补充,而签名/无符号会激怒编译器)。我使用V120 VS2013编译器在C ++中编写了一个快速程序,允许我执行以下操作:
#include <iostream>
main()
{
size_t a = 10;
size_t b = 100;
int result = a - b;
}
该程序导致-90
,虽然这是正确的,但如果size_t恰好用于复杂的数学运算,那么会让我对类型不匹配,有符号/无符号问题或者只是简单的未定义行为感到紧张。
我的问题是,使用size_t对象进行数学运算是否安全,特别是采取差异?我正在考虑使用size_t作为索引之类的标准。我在这里看到了一些关于这个主题的有趣帖子,但它们没有解决数学问题(或者我错过了它)。
答案 0 :(得分:15)
这不保证可以移植,但也不是UB。代码必须无错误地运行,但生成的int
值是实现定义的。因此,只要您在保证所需行为的平台上工作,这很好(只要差异可以由int
表示),否则,只需在任何地方使用带符号的类型(参见最后一段)
减去两个std::size_t
将产生一个新的std::size_t
†,其值将通过换行确定。在您的示例中,假设64位size_t
,a - b
将等于18446744073709551526
。这不适合(常用的32位)int
,因此将实现定义的值分配给result
。
老实说,我建议不要使用无符号整数除了有点神奇之外。标准委员会的几位成员同意我的意见:https://channel9.msdn.com/Events/GoingNative/2013/Interactive-Panel-Ask-Us-Anything 9:50,42:40,1:02:50
经验法则(从上面的视频中解读Chandler Carruth):如果您可以自己计算,请使用int
,否则请使用std::int64_t
。
†除非其转化率低于int
,例如如果std::size_t
是unsigned short
。在这种情况下,结果是int
,一切都会正常工作(除非int
不宽于short
)。然而
答案 1 :(得分:5)
如果你不使用size_t
,你就会被搞砸了:size_t
是一种用于内存大小的类型,因此保证总是足够大那个目的。 (uintptr_t
非常相似,但它既不是第一个这样的类型,也不是标准库使用的,也不是在没有包含stdint.h
的情况下可用。)如果你使用{int
1}},当你的分配超过2GiB的地址空间时,你可以得到未定义的行为(如果你在int
只有16位的平台上,你可以获得32kiB!),即使机器有更多的内存并且你正在执行在64位模式下。
如果您需要size_t
的差异可能会变为负值,请使用已签名的变体ssize_t
。
答案 2 :(得分:4)
size_t
类型未签名。任何两个size_t
值的减法都是定义的 - 行为
然而,首先,如果从较小的值中减去较大的值,则结果是实现定义的。结果是数学值,减少到最小的正余数模SIZE_T_MAX + 1
。例如,如果size_t
的最大值为65535,并且减去两个size_t
值的结果为-3,则结果将为65536 - 3 = 65533。在不同的编译器或具有不同的size_t
,数值将不同。
其次,size_t
值可能超出int
类型的范围。如果是这种情况,我们会得到强制转换产生的第二个实现定义结果。在这种情况下,任何行为都可以适用;它只需要由实现记录,转换不得失败。例如,结果可以被限制在int
范围内,从而产生INT_MAX
。在将较宽(或相等宽度)的无符号类型转换为较窄的有符号类型时,在两个补码机器(几乎所有)上看到的常见行为是简单的位截断:从无符号值中取出足够的位以填充有符号值,包括它的符号位。
由于两个补码的工作方式,如果原始的算术正确的抽象结果本身适合int
,那么转换将产生该结果。
例如,假设在二进制补码机上减去一对64位size_t
值得到抽象算术值-3,它变为正值0xFFFFFFFFFFFFFFFD
。当它被强制转换为32位int
时,在许多编译器中看到的两个补码机器的常见行为是将低32位作为结果int
的图像: 0xFFFFFFFD
。当然,这只是32位的值-3。
结果是,您的代码事实上非常便携,因为几乎所有主流机器都是基于符号扩展和转换规则的两个补充。位截断,包括有符号和无符号之间。
除非在从无符号转换为有符号时将值加宽,否则不会发生符号扩展。因此,他遇到的一个问题是int
比size_t
宽的罕见情况。如果16位size_t
结果为65533,由于从1中减去4,则在转换为32位int
时不会产生-3;它会产生65533!