My program does the common task of writing binary data to a file, conforming to a certain non-text file format. Since the data I'm writing is not already in existing chunks but instead is put together byte by byte at runtime, I use std::ostream::put()
instead of write()
. I assume this is normal procedure.
The program works just fine. It uses both std::stringstream::put()
and std::ofstream::put()
with two-digit hex integers as the arguments. But I get compiler warning C4309: "truncation of constant value" (in VC++ 2010) whenever the argument to put()
is greater than 0x7f. Obviously the compiler is expecting a signed char
, and the constant is out of range. But I don't think any truncation is actually happening; the byte gets written just like it's supposed to.
Compiler warnings make me think I'm not doing things in the normal, accepted way. The situation I described has to be a common one. Is there are common way to avoid such a compiler warning? Or is this an example of a pointless compiler warning that should just be ignored?
I thought of two inelegant ways to avoid it. I could use syntax like mystream.put( char(0xa4) )
on every call. Or instead of using std::stringstream
I could use std::basic_stringstream< unsigned char >
, but I don't think that trick would work with std::ofstream
, which is not a templated type. I feel like there should be a better solution here, especially since ofstream
is meant for writing binary files.
Your thoughts?
--EDIT--
Ah, I was mistaken about std::ofstream
not being a templated type. It is actually std::basic_ofstream<char>
, but I tried that method that and realized it won't work anyway for lack of defined methods and polymorphic incompatibility with std::ostream
.
Here's a code sample:
stringstream ss;
int a, b;
/* Do stuff */
ss.put( 0 );
ss.put( 0x90 | a ); // oddly, no warning here...
ss.put( b ); // ...or here
ss.put( 0xa4 ); // C4309
I found solution that I'm happy with. It's more elegant than explicitly casting every constant to unsigned char
. This is what I had:
ss.put( 0xa4 ); // C4309
I thought that the "truncation" was happening in implicitly casting unsigned char
to char
, but Cong Xu pointed out that integer constants are assumed to be signed, and any one greater than 0x7f gets promoted from char
to int
. Then it has to actually be truncated (cut down to one byte) if passed to put()
. By using the suffix "u", I can specify an unsigned integer constant, and if it's no greater than 0xff, it will be an unsigned char
. This is what I have now, without compiler warnings:
ss.put( 0xa4u );
std::stringstream ss;
ss.put(0x7f);
ss.put(0x80); //C4309
As you've guessed, the problem is that ostream.put()
expects a char
, but 0x7F
is the maximum value for char
, and anything greater gets promoted to int
. You should cast to unsigned char
, which is as wide as char
so it'll store anything char
does and safely, but also make truncation warnings legitimate:
ss.put(static_cast<unsigned char>(0x80)); // OK
ss.put(static_cast<unsigned char>(0xFFFF)); //C4309
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