为了测量流的位置、偏移和大小,标准指定了std::streampos、std::streamoff和std::streamsize,但它们是实现定义的。
如何以安全且可移植的方式将这些类型转换为long long int?(例如测量文件大小并将其注入一个需要long long int作为参数的函数中)
如何以安全且可移植的方式将这些类型转换为long long int?(例如测量文件大小并将其注入一个需要long long int作为参数的函数中)
对于C++98/03,不存在long long int
。因此我假设你在问C++11。
streamsize
和streamoff
必须是整数类型的typedef(streampos
不是整数,因此您不能将其传递给需要long long
的任何函数)。由于整数类型是基本类型,因此它们只能由C++或编译器特定的定义来定义。
因此,唯一的问题是:这些typedef是否比long long
更大?所有整数类型都可以转换为较大或相等大小的类型(有符号/无符号不论,但这里所有类型都是有符号的,所以没有问题)。但是,如果它更大......那么你会怎么做?
假设您无法更改您要“注入”到其中的函数的签名(因为如果您可以,就没有理由不直接将streamsize
作为参数类型并避免问题),则没有任何选项。您有一个数据值,它比函数接受的值更大。这里没有绕过它的方法。
您可以执行静态转换为long long
来关闭编译器,但如果实际大小无法适合long long
,则这将无济于事。
最终,这是一个棘手的问题。您有一个函数接受一个可能过小的参数。您能做的最多就是通过static_assert
检测它可能会出现问题。像这样:
static_assert(sizeof(std::streamsize) <= sizeof(long long), "Oops.");
long long
是您的编译器本地支持的最大整数大小。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是另一个岛屿...
tellg()
返回表示从文件开头计算的字节数的整数类型?对于二进制流,is.seekg(0, std::ios::end)
是未定义行为:“由basic_filebuf<charT, traits>
类对象控制的序列的读取和写入限制与使用标准C库FILE进行读取和写入的限制相同。”请参见https://port70.net/~nsz/c/c11/n1570.html#note268。 - Andrew Henle
streampos
隐式转换为streamoff
,因此您可以将其传递给期望long long
的某些内容。streampos
和streamoff
之间的区别在于对有状态字符编码的支持。 - Potatoswatter