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

时间:2013-10-14 01:50:13

标签: c++ c size-t

对于可以包含全部size_t值的签名类型,是否存在标准(或MSVC专有)typedef?即在64位系统上,它将是一个128位有符号整数。

4 个答案:

答案 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相同?是

Live demo

希望它有所帮助。

答案 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 < 0y > M/2 超出了转换回的范围,但同时您可以进行无符号 y(M) < y(M)+1 或有符号 x(0) > x(0)-1 之类的比较包装后通常会失败,例如 0 < -1 = MM > M+1 = 0 等。

为了记录,我认为最好计算 std::size_t 的相应签名类型,std::make_signed_t<std::size_t>。目前它最有可能是来自 long longunsigned long long,但我不知道它有多普遍,或者它是否会改变。我建议您使用 std::numeric_limits<T> 来检查最小值/最大值。