std::streampos, std::streamoff and std::streamsize to long long int?
Asked Answered
J

3

11

To measure position/offsets/size of streams, the standard specify std::streampos, std::streamoff and std::streamsize, but they are implementation defined.

How to convert these types to long long int in a secure and portable way ? (for example to measure a file size and inject it in a function that take a long long int as argument)

Jimenez answered 8/10, 2012 at 0:29 Comment(0)
A
8

Well, as far as C++98/03 is concerned, there is no long long int. So I'll assume you're asking about C++11.

The streamsize and streamoff are required to be typedefs of an integral type (streampos is not an integer, so you won't be passing that to anything that takes a long long). Since integral types are basic types, they can only be defined by either C++ or as a compiler-specific definition.

Thus, the only question is this: are these typedefs larger than long long? All integral types are convertible to a larger or equal-sized type (signed/unsigned notwithstanding, but all of the types here are signed, so no problem). But if it is larger... what are you going to do about it?

Assuming you can't change the signature of the function you are "injecting" it into (because if you could, there's no reason not to just take streamsize as the parameter type and thus avoid the problem), you don't have any options. You have a data value that is larger than what the function takes. There's no way of getting around it here.

You can perform a static_cast into a long long to shut the compiler up, but this won't help if the actual size can't fit in a long long.

Ultimately, this is an intractable problem. You have a function that takes a parameter which is potentially too small for what you're passing. The most you can do is detect when it might be a problem via a static_assert. Something like this:

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

To be honest, I wouldn't worry about it. Odds are good that long long will be the largest integral size that your compiler natively supports.

Affiliation answered 8/10, 2012 at 0:44 Comment(3)
Apart from the case of exabytes file size, can a problem occur during the conversion to long long int ?Jimenez
@Vincent: No. Integer types can be converted to a larger (or equal-sized) integer type without problem.Affiliation
streampos implicitly converts to streamoff, so you might pass it to something expecting a long long. The difference between streampos and streamoff is support for stateful character encodings.Rig
L
3

Just pass the value to whatever function needs a long long. std::streamoff and std::streamsize are both signed integral types, and std::streampos is implicitly convertible to std::streamoff.

edit: I suppose an assert that streamsize/streamoff is not bigger than long long won't hurt, in case someone comes up with __int128 file sizes.

Lovmilla answered 8/10, 2012 at 0:44 Comment(2)
Seems to be implementation specific, in MINGW-64 / g++ std::streampos is an adapter of std::streamoff, which is a integral type, signed 64-bit integer.Caudate
@SamGinrich that's what I described, no?Lovmilla
C
-1

Short response for MINGW-64: std::streampos has a conversion operator to 64-bit-signed-integer type std::streamoff as

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

So, e.g. to find the length of a file you do not need to do more than opening an std::ifstream and evaluate ...

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;
}

... or think STL was another island ...

Caudate answered 8/2, 2021 at 13:25 Comment(8)
Where in the C++ standard does it specify that tellg() returns an integer type that represents a count of bytes from the start of a file? And is.seekg(0, std::ios::end) is undefined behavior for a binary stream: "The restrictions on reading and writing a sequence controlled by an object of class basic_filebuf<charT, traits> are the same as for reading and writing with the Standard C library FILEs." See port70.net/~nsz/c/c11/n1570.html#note268Guenzi
No idea, where you go with your question. cplusplus.com/reference/istream/istream/tellg Specifications are specifications and use case are use cases and this time disjoint.Caudate
cplusplus.com is not only no reference, it's actually not very accurate. Just because cplusplus.com says something doesn't make it true. What's wrong with cplusplus.com?Guenzi
:) We understand, that "the standard" design does not foresee someone asking for a file size as an integer and insofar is useless.Caudate
If that was meant to be a standard way to get a file size, riddle me this, Batman: Why did C++17 add std::filesystem::file_size? Umm, because it wasn't there before... And I guess you're not aware that once you ask for a file size, it's not longer relevant and using it is a TOCTOU bug waiting to happen? I code to higher standards then TOCTOU bugs and explicit undefined behavior per the language specificationGuenzi
And you've also fallen into the trap that just because something related to a file is an integer value that it must be the file size.Guenzi
Some Upper Cloud Cuckoo Home has no file size.Caudate
finally there is a horizon of hope: we see in C++ 2020, there is a contains-relation for std::set<> ;)Caudate

© 2022 - 2024 — McMap. All rights reserved.