对于可以包含全部size_t
值的签名类型,是否存在标准(或MSVC专有)typedef?即在64位系统上,它将是一个128位有符号整数。
答案 0 :(得分:11)
一般来说,定义这样的类型是不可能的。使size_t
成为支持最大的无符号类型的实现是完全合法的,这意味着没有签名类型可以保存其所有值。
ptrdiff_t
不一定足够广泛。这是减去两个指针的结果,但没有任何说明指针减法不能溢出。请参阅C ++标准的第5.7节:
当减去指向同一数组对象的元素的两个指针时, 结果是两个数组的下标的差异 元素。结果的类型是实现定义的签名 积分型;此类型应与定义的类型相同
std::ptrdiff_t
标题中的<cstddef>
(18.2)。和其他任何一样 算术溢出,如果结果不适合提供的空间, 行为未定义。
最大的签名类型是intmax_t
,在<stdint.h>
或<cstdint>
中定义。这是C99功能,C ++ 11是第一个包含C99标准库的C ++标准,因此您的编译器可能不支持它(而MSVC很可能不支持)。如果签名类型的宽度足以保存size_t
类型的所有可能值,那么intmax_t
就是(尽管可能是一个也符合条件的较窄签名类型)。
您还可以使用long long
,这是一个保证至少为64位的签名类型(很可能与intmax_t
相同)。即使它不足以保存size_t
类型的所有可能值,它几乎肯定会保存size_t
类型的所有相关值 - 除非您的实现实际上支持更大的对象超过8艾字节(即8192千兆字节,或8388608太字节)。
(注意,我使用的是“exa”,“peta-”和“tera-”的二进制定义,这些定义的有效性值得怀疑。)
答案 1 :(得分:2)
我假设你需要这种类型的指针算法。除std::ptrdiff_t
之外,您不太可能需要任何其他内容。这将在现代机器上发挥作用的唯一情况是,当您处于32位模式并且您正在处理超过2 ^ 31字节的数据集时。 (如果没有特殊的工作,这在Windows上甚至是不可能的。)你将无法同时使用那个大小的两个数组。在这种情况下,您应该可以在64位模式下工作。
在64位模式下,在目前的内存开发速度下,未来40年左右很可能不会出现问题。当它成为一个问题,然后在128位模式下编译您的代码,它将继续运行。 ;)
答案 2 :(得分:2)
如果你想要一个可以包含系统最大值的标准类型,那么<cstdint>
(因为C ++ 11)可能有帮助。
该标头中有一个typedef,它包含最大宽度整数类型,类型为intmax_t
。有符号整数的intmax_t
和无符号整数的uintmax_t
是架构完全支持的最大整数。
所以,假设您使用的是64位架构,请遵循以下说明:
std::cout << "intmax_t is same int64_t? "
<< (std::is_same<intmax_t, int64_t>::value ? "Yes" : "No");
将输出:
intmax_t与int64_t相同?是
希望它有所帮助。
答案 3 :(得分:0)
如果您想要一种可以将 std::size_t
的每个值保存为正值的有符号类型,我不知道有什么方法。假设您有相同的位数,则需要一位信息来存储符号,因此新的最大值是旧的一半。另一方面,使用该位的值的上半部分只是包含在负数中,因此您可以随时回滚。
实际上,您可能需要将高无符号/负有符号值与其他任何地方进行转换。如果无符号 0 <= x < M/2 <= y <= M
映射到 0 <= (x, y & (M/2)) < M/2
,则每个值都被考虑在内,但不会在任一方向包装为 x 或 y。如果已签名的 -M/2 <= y < 0 <= x < M/2
映射到 0 <= (x, y+M/2) < M
,则情况相同。
这样您就知道何时 x < 0
或 y > M/2
超出了转换回的范围,但同时您可以进行无符号 y(M) < y(M)+1
或有符号 x(0) > x(0)-1
之类的比较包装后通常会失败,例如 0 < -1 = M
、M > M+1 = 0
等。
为了记录,我认为最好计算 std::size_t
的相应签名类型,std::make_signed_t<std::size_t>
。目前它最有可能是来自 long long
的 unsigned long long
,但我不知道它有多普遍,或者它是否会改变。我建议您使用 std::numeric_limits<T>
来检查最小值/最大值。