繁体   English   中英

获取两个size_t对象的区别是否安全?

[英]Is it safe to take the difference of two size_t objects?

我正在调查我的团队使用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作为索引之类的标准。 我在这里看到了一些关于这个主题的有趣帖子,但是他们没有解决数学问题(或者我错过了它)。

减去2 size_t的类型是什么?

typedef是否可以包含size_t的签名类型?

这不保证可以移植,但也不是UB。 代码必须无错误地运行,但生成的int值是实现定义的。 因此,只要您在保证所需行为的平台上工作,这很好(只要差异可以用int表示),否则,只需在任何地方使用带符号的类型(参见最后一段)。

减去两个std::size_t将生成一个新的std::size_t ,其值将通过换行确定。 在您的示例中,假设64位size_ta - 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_tunsigned short 在这种情况下,结果是一个int ,一切都会正常工作(除非int不比short )。 然而

  1. 我不知道有任何平台可以做到这一点。
  2. 这仍然是特定于平台的,请参见第一段。

如果你不使用size_t ,你就搞砸了: size_t是存在用于内存大小的一种类型,因此保证总是足够大以达到这个目的。 uintptr_t非常相似,但它既不是第一个这样的类型,也不是标准库使用的,也没有包括stdint.h也没有。)如果你使用int ,当你的分配超过2GiB时你可以得到未定义的行为地址空间(或32kiB,如果你在int只有16位的平台上!),即使机器有更多的内存,你正在64位模式下执行。

如果您需要size_t的差异可能变为负数,请使用签名变量ssize_t

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。

因此,结果是, 您的代码事实上非常便携,因为几乎所有主流机器都是基于符号扩展和位截断的转换规则的两个补码,包括有符号和无符号之间。

除非在从unsigned转换为signed时将值加宽时不会发生符号扩展。 因此,他的一个问题是intsize_t更宽的罕见情况。 如果16位size_t结果为65533,由于4从1中减去,当转换为32位int时,这将不会产生-3; 它会产生65533!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM