Есть ли ортодоксальный способ избежать предупреждения компилятора C4309 - "усечение постоянного значения" с выходом двоичного файла?
Моя программа выполняет общую задачу записи двоичных данных в файл, соответствующих определенному формату нетекстового файла. Поскольку данные, которые я пишу, уже не существуют в существующих фрагментах, а вместо этого складываются по байтам во время выполнения, я использую std::ostream::put()
вместо write()
. Я предполагаю, что это обычная процедура.
Программа работает отлично. В качестве аргументов используются как std::stringstream::put()
, так и std::ofstream::put()
с двухзначными шестнадцатеричными целыми числами. Но я получаю предупреждение компилятора C4309: "усечение постоянного значения" (в VС++ 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
Ответы
Ответ 1
Я нашел решение, которым я доволен. Это более элегантно, чем явное приведение каждой константы к unsigned char
. Это то, что у меня было:
ss.put( 0xa4 ); // C4309
Я думал, что "усечение" происходит при неявном нажатии unsigned char
на char
, но Конг Сю отметил, что целочисленные константы считаются подписанными, а любой, превышающий 0x7f, получает от char
до int
. Затем он должен быть усечен (сокращен до одного байта), если он передан на put()
. Используя суффикс "u", я могу указать константу без знака, а если она не больше 0xff, это будет unsigned char
. Это то, что у меня есть сейчас, без предупреждений компилятора:
ss.put( 0xa4u );
Ответ 2
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