Есть ли ортодоксальный способ избежать предупреждения компилятора C4309 - усечение постоянного значения с выводом двоичного файла?

Моя программа выполняет обычную задачу записи двоичных данных в файл в соответствии с определенным нетекстовым форматом файла. Поскольку данные, которые я записываю, уже не находятся в существующих фрагментах, а вместо этого собираются байт за байтом во время выполнения, я использую std::ostream::put() вместо write(). Я предполагаю, что это нормальная процедура.

Программа работает просто отлично. Он использует как std::stringstream::put(), так и std::ofstream::put() с двузначными шестнадцатеричными целыми числами в качестве аргументов. Но я получаю предупреждение компилятора C4309: «усечение постоянного значения» (в VC++ 2010) всякий раз, когда аргумент put() больше 0x7f. Очевидно, что компилятор ожидает 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

person Sam Kauffman    schedule 18.03.2013    source источник
comment
Просто чтобы мы все поняли, можете ли вы добавить конкретный пример кода к своему вопросу?   -  person Oliver Charlesworth    schedule 18.03.2013


Ответы (2)


Я нашел решение, которым я доволен. Это более элегантно, чем явное приведение каждой константы к unsigned char. Вот что у меня было:

ss.put( 0xa4 ); // C4309

Я думал, что «усечение» происходит при неявном приведении unsigned char к char, но Цун Сюй указал, что целые константы считаются знаковыми, и любая константа больше 0x7f повышается с char до int. Затем он должен быть усечен (урезан до одного байта), если передан в put(). Используя суффикс «u», я могу указать целочисленную константу без знака, и если она не больше 0xff, это будет unsigned char. Это то, что у меня есть сейчас, без предупреждений компилятора:

ss.put( 0xa4u );
person Sam Kauffman    schedule 18.03.2013

std::stringstream ss;
ss.put(0x7f);
ss.put(0x80); //C4309

Как вы уже догадались, проблема в том, что ostream.put() ожидает char, но 0x7F является максимальным значением для char, а все, что больше, повышается до int. Вы должны выполнить приведение к unsigned char, ширина которого равна char, чтобы он сохранял все, что делает char, и безопасно, но также делал допустимыми предупреждения об усечении:

ss.put(static_cast<unsigned char>(0x80)); // OK
ss.put(static_cast<unsigned char>(0xFFFF)); //C4309
person congusbongus    schedule 18.03.2013
comment
Почему вы используете ss.put(static_cast<unsigned char>(0x80)); вместо ss.put(unsigned char(0x80)) или ss.put((unsigned char) 0x80)? По какой-то причине предпочтительнее статическое приведение? - person Sam Kauffman; 19.03.2013
comment
@SamKauffman, это просто современный способ приведения типов C ++. Это более многословно, но менее двусмысленно и безопаснее. - person Mark Ransom; 19.03.2013
comment
@CongXu, спасибо! То, что вы написали о продвижении, помогло мне понять, что на самом деле происходит усечение. - person Sam Kauffman; 19.03.2013
comment
@SamKauffman ss.put(unsigned char(0xFFFF)); ‹--- без предупреждения. Вот почему приведения C++ предпочтительнее приведения C. - person congusbongus; 19.03.2013