【问题标题】:typedef for a signed type that can contain a size_t?typedef 用于可以包含 size_t 的有符号类型?
【发布时间】:2013-10-14 01:50:12
【问题描述】:

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

【问题讨论】:

  • 糟糕,标题中的错字。我问的是签名类型。
  • 如果你想要一个有符号类型的原因是为了重载/转义它具有特殊含义,你可以考虑boost::optional<> 包装器。
  • 为什么是 128 位? 65 就足够了。
  • 好吧,你是对的,我只是假设尺寸是 2 的幂 :)
  • 这能回答你的问题吗? Can I use 128-bit integer in MSVC++?

标签: c++ c size-t


【解决方案1】:

通常不可能定义这样的类型。使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 PB 或 8388608 TB)。

(注意,我使用的是“exa-”、“peta-”和“tera-”的二进制定义,它们的有效性值得怀疑。)

【讨论】:

  • "而 MSVC 很可能不会" - 作为旁注,新的整数类型确实是 MSVC 为数不多的 C++11 特性之一 标准库自 2010 以来就有。
  • 此外,如果您不确定在给定平台上要获得什么尺寸,请添加:static_assert(sizeof(intmax_t) > sizeof(size_t), "Can't get a signed type guaranteed to hold a size_t");,这样编译器会在您可能遇到麻烦时警告您.
【解决方案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.

希望对你有帮助。

【讨论】:

  • 不是 size_t 的签名版本。 intmax_t 在 x64 上是 8 字节(与 size_t 相同),但在 32 位上也是 8 字节,而在这种情况下 size_t 是 4 字节。
【解决方案3】:

我假设您需要这种类型来进行某种指针运算。除了std::ptrdiff_t,您不太可能需要其他任何东西。这将在现代机器上发挥作用的唯一情况是当您处于 32 位模式并且您正在处理超过 2^31 字节的数据集时。 (如果没有特殊工作,这甚至在 Windows 上都不可能。)您将无法同时使用两个该大小的数组。在这种情况下,您可能无论如何都应该在 64 位模式下工作。

在 64 位模式下,以目前的内存发展速度,在未来 40 年左右的时间里,它很可能不会成为问题。当它成为一个问题时,然后在 128 位模式下编译你的代码,它会继续运行。 ;)

【讨论】:

    【解决方案4】:

    如果您想要一个可以将std::size_t 的每个值作为正值 的有符号类型,我不知道有什么办法。假设您有相同的位数,存储符号需要一位信息,所以新的最大值是旧的一半。另一方面,使用该位的值的上半部分只是包裹在负数中,因此您始终可以回滚。

    真的,您可能需要将高无符号/负符号值与其他值分开,无论您将它们投射到何处。如果无符号 0 &lt;= x &lt; M/2 &lt;= y &lt;= M 映射到 0 &lt;= (x, y &amp; (M/2)) &lt; M/2,则每个值都会被计算在内,但不会在任一方向上包装为 x 或 y。如果签名的-M/2 &lt;= y &lt; 0 &lt;= x &lt; M/2 映射到0 &lt;= (x, y+M/2) &lt; M 也是一样的。

    这样您就知道何时x &lt; 0 或y &gt; M/2 超出了转换回的范围,但同时您可以进行比较,如无符号y(M) &lt; y(M)+1 或有符号x(0) &gt; x(0)-1,通常在包装后失败,如@ 987654330@、M &gt; M+1 = 0等

    为了记录,我相信std::size_t 的对应签名类型是最好的计算方法,std::make_signed_t&lt;std::size_t&gt;。目前它很可能是来自unsigned long long 的long long,但我不知道它有多普遍,或者它是否会改变。无论如何,我建议使用std::numeric_limits&lt;T&gt; 从那里检查最小值/最大值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-13
      • 1970-01-01
      • 2021-08-26
      • 1970-01-01
      • 2021-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多