C++ uses the streamoff
type to represent an offset within a (file) stream and is defined as follows in [stream.types]:
using streamoff = implementation-defined ;
The type streamoff is a synonym for one of the signed basic integral types of sufficient size to represent the maximum possible file size for the operating system. 287)
287) Typically long long.
This makes sense because it allows for seeking within large files (as opposed to using long
, which may be only 32 bits wide).
[filebuf.virtuals] defines basic_filebuf
's function to seek within a file as follows:
pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override;
off_type
is equivalent to streamoff
, see [iostreams.limits.pos]. However, the standard then goes on to explain the function's effects. I'm irritated by the very last sentence, which requires a call to fseek
:
Effects: Let
width
denotea_codecvt.encoding()
. Ifis_open() == false
, oroff != 0 && width <= 0
, then the positioning operation fails. Otherwise, ifway != basic_ios::cur
oroff != 0
, and if the last operation was output, then update the output sequence and write any unshift sequence. Next, seek to the new position: ifwidth > 0
, callfseek(file, width * off, whence)
, otherwise callfseek(file, 0, whence)
.
fseek
accepts a long
parameter. If off_type
and streamoff
are defined as long long
(as suggested by the standard), this could lead to a down conversion to long
when calling fseek(file, width * off, whence)
(leading to potentially hard to diagnose bugs). This calls into question the whole rationale for introducing the streamoff
type in the first place.
Is this intentional or a defect in the standard?
A stream is a logical entity that represents a file or device, that can accept input or output. All input and output functions in standard C, operate on data streams. Streams can be divided into text, streams and binary streams.
The fseek() function changes the current file position associated with stream to a new location within the file. The next operation on the stream takes place at the new location. On a stream opened for update, the next operation can be either a reading or a writing operation.
Having created a stream, we can connect it to a file using the member function "open(...)".
I think that the conclusion that you're drawing from this, that there is a mismatch between C++ streams and fseek
that will lead to runtime bugs, is incorrect. The situation seems to be:
On systems where long
is 64 bits, streamoff
is defined as long
, and the seekoff
function invokes fseek
.
On systems where long
is 32 bits but the OS supports 64-bit file offsets, streamoff
is defined as long long
and seekoff
invokes a function called either fseeko
or fseeko64
that accepts a 64-bit offset.
Here's s snippet from the definition of seekoff
on my Linux system:
#ifdef _GLIBCXX_USE_LFS
if (!fseeko64(_M_file, __off, __whence))
__ret = std::streampos(ftello64(_M_file));
#else
if (!fseek(_M_file, __off, __whence))
__ret = std::streampos(std::ftell(_M_file));
#endif
LFS stands for Large File Support.
Conclusion: While the standard suggests a definition for streamoff
that ostensibly conflicts with the requirement that seekoff
invoke fseek
, library designers understand that they must call the variant of fseek
that accepts the full range of offsets that the OS supports.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With