【问题标题】:How do all the different size types relate to each other?所有不同的尺寸类型如何相互关联?
【发布时间】:2011-07-12 19:59:06
【问题描述】:

目前我有一个场景,我想检查将给定字符串写入文件流是否会使文件增长超过给定大小(这用于日志文件轮换)。现在,std::ofstream::tellp() 返回 streampos,但 std::string::size() 返回 size_t。效果是,这不起作用:

out_stream.tellp() + string.size() < limit

因为这些类型显然存在 operator + 的模棱两可的重载。这引出了两个问题:

  1. 如何解决上述歧义?
  2. 所有不同的类型(size_tstreamsizestreamposstreamoff)如何相互关联?什么时候可以安全地转换它们,以及可能的陷阱是什么。我通常对这些类型感到困惑。我所知道的是它们依赖于实现,并且它们做出了某些保证(例如,size_t 总是足够大,可以容纳适合编译应用程序的体系结构内存中的 larges 对象的大小),但是这些类型的互操作性有哪些保证(参见上面的示例,或将streamsizesize_t 进行比较)?

【问题讨论】:

  • std::string::size() 返回一个std::string::size_type,不能保证是size_t
  • @Etienne:感谢您澄清这一点。不幸的是,这只会让事情变得更复杂。
  • @Etienne:对大多数人来说是这样(即,当没有使用自定义分配器时):stackoverflow.com/questions/918567/size-t-vs-containersize-type

标签: c++ size-type


【解决方案1】:

您应该能够通过强制转换将结果从 tellp 转换为 std::string::size_type

static_cast&lt;std::string::size_type&gt;(out_stream.tellp()) + string.size() &lt; limit

编辑:这是安全的,因为您的流偏移量永远不会是负数,并且会安全地转换为无符号值。

【讨论】:

  • 我知道这是可能的,但是安全吗?
  • @Space_C0wb0y 因为它是一个 static_cast (不是重新解释),如果转换没有意义,编译器会抱怨。应该是安全的。
  • std::string::size_type 未签名,std::streampos 未签名。但它应该是安全的。
  • @EtiennedeMartel:如果没有一些边界检查,或者至少有一些关于尺寸的静态断言,这根本不安全。 streamoff 很可能是 64 位,size_t 很可能是 32 位。 (事实上​​,这正是你在 32 位 POSIX 系统上定义 _FILE_OFFSET_BITS=64 时得到的结果,这是不久前非常常见的编译模式。)
【解决方案2】:

真正的问题是:限制的类型是什么?通常的方式 测试是否还有空间通常是: 限制 - out_stream.tellp() >= string.size() 但是你必须确保 limit 有一个类型 out_stream.tellp() 可以减去。

理论上,streampos 不可转换,也不能与积分相比较 类型,或者那个,转换为整数类型,它给出了显着的 信息。为此,它需要支持减法或比较 事情。在实践中,我认为你不必太担心 转换为存在的整数类型,并且是单调的(尽管 也许在一些异国情调的大型机上......)。但你不能确定 用它算术会起作用,所以我可能更喜欢转换它 显式到流大小(保证是有符号积分 类型)。 (不管你如何处理这个问题,你都必须处理 事实上 string.size() 返回一个 size_t,这是必需的 是未签名的,而streamsize需要签名。)

关于你的第二个问题: size_t 是无符号整数类型的 typedef,大到足以 指定任何可能对象的大小, streamsize 是有符号整数类型的 typedef,大到足以 指定流中“对象”的大小, streamoff 是能够指定的整数类型的 typedef 一个字节在文件中的位置,以及 streampos 是 fpos 的 typedef,其中 something 是一种可用于维护状态的类型 多字节流的情况。 该标准对关系的要求很少 它们之间(其中一些在数学上是不可能的 意识到),所以你几乎是靠自己的。

【讨论】:

    【解决方案3】:

    我相信标准说streamsize 是特定于实现的,所以那里没有帮助。对于一个实际的答案,您可以检查这些是typedefed 的标题。

    考虑到 size_t 可能是 4 个字节,而您的应用程序可能可以在超过 4GB 长度的流上运行,我相信您应该转换为已知大小合适的类型以进行互操作密封解决方案。

    当然,如果您知道(可能通过编译时断言)size_tstreamsize 是 8 个字节长,您可以直接使用该类型。如果您有一个长度不适合 8 个字节的流,那么您会遇到比转换为正确类型更严重的问题。

    【讨论】:

    • 检查 typedefs 并没有真正帮助我,因为我想要可移植的代码。问题是,是否有任何保证,例如 streamsize 总是适合 size_t
    • @Space_C0wb0y:我找不到。但是如果不合适,使用合适的编译时断言将不会让你编译,所以你被覆盖了。为了获得最大的便携性,请使用您自己的typedef。然后你可以使用#ifdef 来检测平台/编译器和#include 一个带有typedef 定义的标头,就像任何大型可移植C++ 库一样。
    【解决方案4】:

    如果你有大尺寸,unsigned long long不是你能得到的最好的。如果这还不够大,还有什么?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-22
      • 2011-11-08
      • 2018-01-27
      • 2020-05-16
      相关资源
      最近更新 更多