【问题标题】:What type for subtracting 2 size_t's?减去 2 size_t 的类型是什么?
【发布时间】:2012-12-21 13:17:17
【问题描述】:

C 中应该使用哪种类型来表示两个对象大小之间的差异?

由于size_t 是未签名的,类似于

size_t diff = sizeof (small_struct) - sizeof (big_struct);

显然不正确,在我看来,没有真正的签名等价物。

ptrdiff_t 听起来有点诱人,但是

  1. 正如它的名字所说,它是用于减去指针。
  2. 我读过,例如像 DOS 这样的分段平台具有 64k 的最大对象大小,可以用 16 位表示。然而,远指针由一个 16 位段值和一个 16 位偏移值组成。这不会使ptrdiff_t 在这样的平台上也成为 32 位吗? 如果是这样,两个对象之间的大小差异只需要 16 位,但使用 ptrdiff_t 会给您一个 32 位宽的变量,使其不是最佳的。

那么,使用这种值的合适的可移植类型是什么?

Edit: 我知道 ssize_t,但它是

  1. 不是标准 C 的一部分。
  2. 实际上并非用于此类用途,而是用于返回大小或(负)错误值。

【问题讨论】:

  • @AFAIK ssize_t 是 POSIX,而不是 ISO C。
  • @RomanR。 ssize_t 不是 C 标准,size_t 的值不能保证适合 POSIX 中的 ssize_t
  • 这个问题的问题在于它没有解释它应该是什么意思。您可以设想在某种程度上增加结构尺寸,例如用于计算布局,尽管由于结构对齐规则,这已经很麻烦了。结构尺寸的差异真正代表什么?这段代码出现在什么上下文中?如果你不能解释,那么你也不能为它编写正确的代码。
  • @Mehrdad: C11, 6.5.7/9: "当两个指针相减时,[...] 结果的大小是实现定义的,其类型(有符号整数类型)是在 头文件中定义的 ptrdiff_t。如果结果在该类型的对象中不可表示,则行为未定义。” 因此,不能保证(尽管这指的是指针地址,因为这是 ptrdiff_t 的用途,而不是对象大小)。
  • @netcoder:没错,但这不是全部。你不能减去任意指针;它们必须指向同一个对象。因此,如果ptrdiff_t 可以保持它们的差异(假设一个指针指向对象的开头,另一个指向对象的结尾),并且size_t 可以保持对象的大小,根据定义在两者不能丢失信息。不过,它是否溢出符号位当然是一个不同的问题——但这些位是存在的。

标签: c size-t


【解决方案1】:

当我真的很担心这样的溢出问题时(尤其是在模算术中工作时,其中“负”值包裹在 ~0 以外的某个地方时)我只是将其分为两种情况:

if (a > b) {
    size_t diff = a - b;
} else {
    size_t diff = b - a;
    // code here subtracts diff rather than adds it, etc.
}

【讨论】:

    【解决方案2】:

    你可以这样做:

    size_t diff = std::abs(static_cast <int> (sizeof (small_struct) - sizeof (big_struct)));
    

    【讨论】:

      【解决方案3】:

      对于您正在尝试做的事情,没有一种标准数据类型可以保证 100% 安全。作为证据,想象一下size_t 是否真的只是uint64_t,这是完全可能的。那么就没有标准的 C 数据类型可以保证有一个与 uint64_t 匹配的正范围并且还可以处理负值。

      所以对您的问题的直截了当的回答是“没有数据类型”(假设严格遵守标准 C,您似乎希望这样做)。

      但是,您并不清楚您的用例,您可能能够利用模运算来处理“负”值。例如,the following code 导致 d2 成为 4,因为模运算,允许代码像 size_t 被签名一样:

      #include <stdio.h>
      #include <stdint.h>
      
      int main()
      {
          size_t d1 = sizeof(int32_t) - sizeof(int64_t);
          size_t d2 = sizeof(int64_t) + d1; // Add difference (even if d1 is "negative"*)
      
          printf("d1: %zu\n", d1);
          printf("d2: %zu\n", d2);
      
          return 0;
          // * By "negative" I mean that d1 would be negative if size_t were signed
      }
      

      在你的情况下,模数运算可能对你来说不够,但对其他人来说可能。

      【讨论】:

        【解决方案4】:

        没有符号 C 整数类型可以保存来自 size_t 值的所有值。

        【讨论】:

        • 在您的实施中?还是标准明确禁止的? :)
        • 我的意思是在所有实现中。当然,在某些实现中,所有size_t 值都可以放入有符号整数类型中。
        猜你喜欢
        • 2023-04-03
        • 2014-05-17
        • 1970-01-01
        • 2019-01-13
        • 2013-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-27
        相关资源
        最近更新 更多