2013-03-18 2 views
15

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

Программа работает нормально. Он использует как аргументы 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 предназначен для написания двоичных файлов.

Ваши мысли?

--EDIT--

Ах, я ошибся 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 
+4

Как раз так мы все поняли, можете ли вы добавить конкретный пример кода на свой вопрос? –

+1

Я уверен, что у создателей компилятора не хватает времени для создания «бессмысленных» предупреждений. –

ответ

17

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

ss.put(0xa4); // C4309 

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

ss.put(0xa4u); 
7
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 
+1

Почему вы используете 'ss.put (static_cast (0x80)); вместо' ss.put (unsigned char (0x80)) 'или' ss.put ((unsigned char) 0x80) '? Почему-то статическая броска предпочитается? –

+1

@SamKauffman, это просто современный C++ способ делать броски. Это словеснее, но менее двусмысленно и безопаснее. –

+0

@CongXu, спасибо! То, что вы писали о продвижении по службе, помогло мне понять, что происходит на самом деле. –