【问题标题】:std::streampos, std::streamoff and std::streamsize to long long int?std::streampos、std::streamoff 和 std::streamsize 到 long long int?
【发布时间】:2012-09-28 06:00:02
【问题描述】:

为了测量流的位置/偏移量/大小,标准指定了std::streamposstd::streamoffstd::streamsize,但它们是由实现定义的。

如何以安全且可移植的方式将这些类型转换为long long int? (例如测量文件大小并将其注入以 long long int 作为参数的函数)

【问题讨论】:

    标签: c++ file c++11 stream standards-compliance


    【解决方案1】:

    嗯,就 C++98/03 而言,没有long long int。所以我假设你问的是 C++11。

    streamsizestreamoff 必须是整数类型的 typedef(streampos 不是整数,因此您不会将其传递给任何需要 long long 的东西)。由于整数类型是基本类型,它们只能由 C++ 定义或作为特定于编译器的定义。

    因此,唯一的问题是:这些类型定义大于long long 吗?所有整数类型都可以转换为更大或相等大小的类型(尽管有符号/无符号,但这里的所有类型都是有符号的,所以没问题)。但如果它更大……你打算怎么办?

    假设您无法更改要“注入”它的函数的签名(因为如果可以,没有理由不将streamsize 作为参数类型,从而避免问题),您不要没有任何选择。您的数据值大于函数采用的值。这里没有办法绕过它。

    您可以对 long long 执行 static_cast 以关闭编译器,但如果实际大小无法容纳在 long long 中,这将无济于事。

    最终,这是一个棘手的问题。您有一个函数,该函数接受的参数对于您传递的内容可能太小。您最多可以通过static_assert 检测何时可能出现问题。像这样的:

    static_assert(sizeof(std::streamsize) <= sizeof(long long), "Oops.");
    

    说实话,我不会担心。 long long 很有可能是您的编译器本机支持的最大整数大小。

    【讨论】:

    • 除了文件大小为 exabytes 的情况外,在转换为 long long int 的过程中是否会出现问题?
    • @Vincent:不。整数类型可以毫无问题地转换为更大(或相等大小)的整数类型。
    • streampos 隐式转换为streamoff,因此您可以将其传递给期望long long 的对象。 streamposstreamoff 之间的区别在于对有状态字符编码的支持。
    【解决方案2】:

    只需将值传递给需要 long long 的任何函数。 std::streamoffstd::streamsize 都是有符号整数类型,std::streampos 可以隐式转换为 std::streamoff

    编辑:我认为 streamsize/streamoff 不大于 long long 的断言不会有什么坏处,以防有人提出 __int128 文件大小。

    【讨论】:

    • 似乎是特定于实现的,在 MINGW-64 / g++ std::streampos 是 std::streamoff 的一个适配器,它是一个整数类型,有符号的 64 位整数。
    • @SamGinrich 这就是我所描述的,不是吗?
    【解决方案3】:

    MINGW-64 的短响应:std::streampos 有一个转换为 64 位有符号整数类型 std::streamoff 的运算符

    std::streampos pos = ...;
    std::streamoff ofs = (std::streamoff) pos;
    

    所以,例如要查找文件的长度,您只需打开std::ifstream 并评估...

    static unsigned long long getStreamSize(std::ifstream& is)
    {
        std::streampos savePos = is.tellg();
        is.seekg(0, std::ios::end);
        std::streampos endPos = is.tellg();
        is.seekg(savePos);
        return (std::streampos)endPos;
    }
    

    ...或者认为 STL 是另一个岛屿 ...

    【讨论】:

    • 它在 C++ 标准中的什么地方指定 tellg() 返回一个整数类型,该类型表示从文件开头开始的字节数?而is.seekg(0, std::ios::end) 是二进制流的未定义行为:“读取和写入由类basic_filebuf&lt;charT, traits&gt; 的对象控制的序列的限制与使用标准C 库文件读取和写入的限制相同。”见port70.net/~nsz/c/c11/n1570.html#note268
    • 不知道,你的问题去哪里了。 cplusplus.com/reference/istream/istream/tellg 规范就是规范,用例就是用例,这一次是不相交的。
    • cplusplus.com 不仅没有参考,实际上也不是很准确。仅仅因为 cplusplus.com 说了什么并不能使它成为真的。 What's wrong with cplusplus.com?
    • :) 我们理解,“标准”设计并没有预见到有人要求将文件大小作为整数,因此是无用的。
    • 如果这是一种获取文件大小的标准方法,请给我一个谜语,蝙蝠侠:为什么 C++17 会添加 std::filesystem::file_size?嗯,因为它以前不存在......而且我猜你没有意识到一旦你要求文件大小,它就不再相关并且使用它是一个 TOCTOU bug 等待发生?我按照语言规范编写了更高的标准,然后是 TOCTOU 错误和明确的未定义行为
    猜你喜欢
    • 2014-08-17
    • 2021-12-17
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多