我的程序执行将二进制数据写入文件的常见任务,符合某种非文本文件格式。由于我正在编写的数据不是已经存在于现有块中,而是在运行时逐字节放在一起,因此我使用std::ostream::put()
而不是write()
。我认为这是正常的程序。
程序运行正常。它使用std::stringstream::put()
和std::ofstream::put()
两个十六进制整数作为参数。但是每当put()
的参数大于0x7f时,我都会收到编译器警告C4309:“截断常量值”(在VC ++ 2010中)。显然编译器期望signed char
,并且常量超出范围。但我认为任何截断都不会发生;字节的写入就像它应该的那样。
编译器警告让我觉得我没有以正常,可接受的方式做事。我描述的情况必须是一个普遍的情况。 是否有通用的方法来避免这种编译器警告?或者这是一个无意义的编译器警告的例子,应该被忽略?
我想到了避免它的两种不太优雅的方法。我可以在每次调用时使用mystream.put( char(0xa4) )
之类的语法。或者不是使用std::stringstream
我可以使用std::basic_stringstream< unsigned char >
,但我不认为这个技巧适用于std::ofstream
,这不是模板化类型。我觉得这里应该有一个更好的解决方案,特别是因为ofstream
用于编写二进制文件。
你的想法?
- 编辑 -
啊,我错误地认为std::ofstream
不是模板类型。它实际上是std::basic_ofstream<char>
,但我尝试了这种方法并且意识到它无法用于缺少定义的方法和与std::ostream
的多态不兼容。
以下是代码示例:
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
答案 0 :(得分:18)
我找到了我很满意的解决方案。它比将每个常量明确地转换为unsigned char
更优雅。这就是我所拥有的:
ss.put( 0xa4 ); // C4309
我认为“截断”是在隐式地将unsigned char
转换为char
时发生的,但是Cong Xu指出假定整数常量是有符号的,并且大于0x7f的任何一个都是从char
到int
。然后,如果传递给put()
,它必须实际被截断(减少到一个字节)。通过使用后缀“u”,我可以指定无符号整数常量,如果它不大于0xff,则它将是unsigned char
。这就是我现在所拥有的,没有编译器警告:
ss.put( 0xa4u );
答案 1 :(得分:7)
std::stringstream ss;
ss.put(0x7f);
ss.put(0x80); //C4309
正如您所猜测的那样,问题是ostream.put()
需要char
,但0x7F
是char
的最大值,而更高的内容会被提升为int
{1}}。您应该转换为unsigned char
,这与char
一样宽,因此它会安全地存储char
所做的任何事情,但也会使截断警告合法化:
ss.put(static_cast<unsigned char>(0x80)); // OK
ss.put(static_cast<unsigned char>(0xFFFF)); //C4309