有没有一种正统的方法可以避免编译器警告C4309 - 使用二进制文件输出"截断常量值"?

Sam*_*man 16 c++ file-io binary-data truncation compiler-warnings

我的程序执行将二进制数据写入文件的常见任务,符合某种非文本文件格式.由于我正在编写的数据不是已经在现有的块中,而是在运行时逐字节放在一起,我使用std::ostream::put()而不是write().我认为这是正常的程序.

该程序工作得很好.它使用两个std::stringstream::put()std::ofstream::put()两位十六进制整数作为参数.但是只要参数to put()大于0x7f,我就会得到编译器警告C4309:"截断常量值"(在VC++ 2010中).显然编译器期望a 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
Run Code Online (Sandbox Code Playgroud)

Sam*_*man 18

我找到了我很满意的解决方案.它比将每个常量明确地转换为更优雅unsigned char.这就是我所拥有的:

ss.put( 0xa4 ); // C4309
Run Code Online (Sandbox Code Playgroud)

我认为,"截断"是发生在隐含铸造unsigned charchar,但琮须指出的是整数假定常量要签名,并且大于0x7F任何人会从提升charint.然后,如果传递给它,它实际上必须被截断(减少到一个字节)put().通过使用后缀"u",我可以指定一个无符号整数常量,如果它不大于0xff,它将是一个unsigned char.这就是我现在所拥有的,没有编译器警告:

ss.put( 0xa4u );
Run Code Online (Sandbox Code Playgroud)


con*_*gus 7

std::stringstream ss;
ss.put(0x7f);
ss.put(0x80); //C4309
Run Code Online (Sandbox Code Playgroud)

正如您所猜测的那样,问题是ostream.put()期望a char,但是0x7F是最大值char,并且任何更大的值都会被提升int.你应该转换为unsigned char,它会尽可能广泛char存储任何char安全的东西,但也会使截断警告合法:

ss.put(static_cast<unsigned char>(0x80)); // OK
ss.put(static_cast<unsigned char>(0xFFFF)); //C4309
Run Code Online (Sandbox Code Playgroud)

  • @SamKauffman`ss.put(unsigned char(0xFFFF));`<---没有警告.这就是为什么C++演员比C演员更受欢迎的原因. (2认同)