Reputation: 3417
As far as I know, read()
and write()
are there so we can read and write bytes directly from or to a file, and I was taught that the equivalent of a byte
in c++ is unsigned char
, so why do they take char
pointers as parameters?
Also, do take a look at this function from a "bmp file image reader" library I found:
bool BMPImage::readInfo()
{
//...
//read bmp and dib headers
unsigned char header[28] = {0};
_ifs->read((char*)header, 28);
_width = *(int*)&header[18]; //width is located in [18] and is 4 bytes size
_height = *(int*)&header[22]; //height is located in [22] and is 4 bytes size
_bpp = (unsigned char) *(short*)&header[28]; //bpp is located in [28] and is 2 bytes size
_channels = _bpp / 8; //set num channels manually
//...
Why does the _ifs->read()
line work anyway? The cast from unsigned char to char forces loss of data, no?
Upvotes: 3
Views: 1246
Reputation: 3341
In C and C++, the standards do not specify whether char
is signed or unsigned, and implementations are free to implement it as either. There are separate types signed char
(guaranteed to hold at least the range [-127,127]) and unsigned char
(guaranteed to hold at least the range [0,255]), and char
will be equivalent to one of them, but it is implementation defined as to which it is.
Given that the ASCII character set only contains values 0 to 127, it makes sense that, historically, a single signed byte would have been seen as adequate for holding a single character, while still using the same convention as larger types, where integral types are signed by default unless explicitly declared as unsigned
.
Upvotes: 1
Reputation: 238301
was taught that the equivalent of a
byte
in c++ isunsigned char
I don't know what byte
is, but you can use char
to represent a byte just fine.
so why do [fstream.read and fstream.write] take char pointers as parameters?
fstream
is an alias of std::basic_fstream<char>
. std::basic_fstream
is a template whose all operations deal with its specified char_type
. Since that char_type
is char
, all operations deal with char
, not unsigned char
.
You could use basic_fstream<unsigned char>
as Juan suggested, but it's more involved than that. You will need to specialize char_traits<unsigned char>
which is the second (defaulted) template argument of basic_fstream<unsigned char>
.
The cast from unsigned char to char forces loss of data, no?
No. Accessing unsigned char
through a char*
loses no data. In fact, accessing any type through char*
will not lose data.
This on the other hand:
*(int*)&header[18]
has undefined behaviour, unless the buffer was properly aligned such that header[18]
happens to be located at the boundary required by int
. I see no such guarantees in the definition of the array. Some architectures do not support unaligned memory access at all.
Upvotes: 0
Reputation: 6632
Given that char
and unsigned char
have the same size, there should be no data loss when converting between them.
Said that, have in mind that fstreamm
is just an specialization of std::basic_fstream
for chars:
// from <fstream>
typedef basic_fstream<char> fstream;
You can create your own type for unsigned char, like this:
typedef basic_fstream<unsigned char> ufstream;
Upvotes: 0