Параметры для подавления сравнения всегда ложны из-за ограниченного диапазона предупреждений о типах данных.

Учитывая некоторый код, например:

unsigned short val;
//<some unimportant code that sets val>

if(val>65535) val=65535;

Как мы можем отключить предупреждение «сравнение всегда ложно из-за ограниченного диапазона типов данных» от gcc?

Это использует GCC 4.1.2 и поэтому не имеет конструкции #pragma GCC diagnostics. Я также не могу найти параметр -W, чтобы отключить его.

Я попытался сделать бросок val:

if(((long)val)>65535); val=65535

Но кажется, что GCC достаточно умен, чтобы выдать предупреждение.

Флаги компилятора -Wall, и это все. Нет — Wextra.

Я действительно не хочу убирать галочку - на этой цели short может быть 16-битным, но это не значит, что так и должно быть. Я счастлив выписать чек по-другому, хотя.

Я хочу включить -Werror, поэтому это предупреждение должно исчезнуть.

EDIT 1 Неважный код не так уж и не важен:

unsigned short val;
float dbValue; (actually function parameter)
val= ((unsigned short) dbValue) & 0xffff);
if(val>65535) val=65535;

Таким образом, если размер коротких изменений изменится, мы получим переполнение, и в любом случае проверка диапазона становится все равно бессмысленной и может быть удалена или более того, чтобы вместо этого применить точку к значению с плавающей запятой.

EDIT 2 Хотя ответы до сих пор помогли улучшить код, все же было бы полезно узнать, есть ли какие-либо средства для отключения этого предупреждения в gcc 4.1.2 - вот в чем был вопрос.

Кажется, это можно сделать в последних выпусках, используя -Wno-type-limits


person mjs    schedule 20.11.2014    source источник
comment
Итак, вы хотите насыщающее 16-битное целое число без знака?   -  person EOF    schedule 20.11.2014
comment
Эта проверка ((val-65535)›0) помогает?   -  person Minh Mai    schedule 20.11.2014
comment
Почему вы хотите отключить предупреждение? Он говорит вам, что ваш тест бесполезен как таковой. Если вы хотите обнаружить переполнение, вы должны сделать это заранее, то есть вы должны применить это в коде, который вы считаете неважным.   -  person M Oehm    schedule 20.11.2014
comment
@EOF возможно. Кажется, это и есть намерение. Это не мой код, я просто нахожусь в крестовом походе предупреждений.   -  person mjs    schedule 20.11.2014
comment
@MOehm: Вам не необходимо проверять перед переполнением, потому что unsigned переполнение определено как дополнение до 2 в C. Именно signed запускает UB.   -  person EOF    schedule 20.11.2014
comment
Кажется, проблема с предпосылкой этого вопроса. Может ли val иметь значения выше 65535 перед входом в условие? Если это возможно, то unsigned short не подходит для типа. В противном случае у вас будет разное поведение на 16-битном (переход) и 32-битном (ограничения) short .   -  person user694733    schedule 20.11.2014
comment
@MOehm Это бесполезно, учитывая текущий компилятор и цель, но этот же код, возможно, потребуется запустить в ближайшем будущем на цели, у которой нет 16-битного короткого замыкания.   -  person mjs    schedule 20.11.2014
comment
@EOF: Да, но как узнать, является ли целое число без знака результатом вычисления с переполнением или нет?   -  person M Oehm    schedule 20.11.2014
comment
Ничего себе, это, кажется, вызывает больше споров, чем ожидалось!   -  person mjs    schedule 20.11.2014
comment
Это бесполезно, учитывая текущий компилятор и цель Я написал как есть. Но если вы нацеливаетесь на платформы с большими шортами, поведение на этих двух платформах будет разным. Скажем, неважный код дает непереполненный результат 65538. 16-битный короткий код будет иметь 2, большой короткий код будет иметь результат 65535.   -  person M Oehm    schedule 20.11.2014
comment
Разве dbValue && 0xffff не гарантирует, что результат будет ‹= 65535, независимо от размера?   -  person    schedule 20.11.2014
comment
if(val >= 65535) val = 65535; заставит компилятор замолчать.   -  person joop    schedule 20.11.2014
comment
@Аркадий да, бывает. Я не заметил этого до редактирования вопроса, так как он был скрыт внутри некоторых макросов. Однако вопрос о том, как заставить компилятор замолчать, по-прежнему актуален. Просто, возможно, не по уважительной причине :-) Мне нравятся предложения использовать USHRT_MAX в качестве проверки.   -  person mjs    schedule 20.11.2014


Ответы (4)


Теоретически нет ответа на ваш вопрос: если то, что вы намереваетесь написать, не является операцией (для конкретной целевой архитектуры) для всех возможных значений val, с которыми может быть достигнут код, тогда компилятор может предупредить, что это беспроигрышный вариант для всех…

На практике сравнения (val + 0) вместо val может быть достаточно, чтобы позволить компилятору выдать тот же код, что и с вашей исходной версией, и при этом помолчать об этом.

я бы порекомендовал вам написать

#include <limits.h>
…
#if USHRT_MAX > 65535
if(val>65535) val=65535;
#endif

Я чувствую, что если бы вы использовали его без комментариев, это сделало бы намерение более ясным, чем любой запутанный трюк.

person Pascal Cuoq    schedule 20.11.2014
comment
Это то, на что я надеялся, хотя я думал о UINT16_MAX, который, очевидно, не поможет. - person mjs; 20.11.2014

Вы можете использовать условную компиляцию:

#include <limits.h>

unsigned short val;

#if USHRT_MAX > 65535
  if(val>65535) val=65535;
#endif
person Nisse Engström    schedule 20.11.2014

Использование макроса min:

#define min(x, y)   (((x) < (y)) ? (x) : (y))
val=min(val,65535);

избавится от предупреждения. Таким образом, мы также можем использовать ту же реализацию напрямую

val=(val)<(65535)? val: 65535;

Хитрость здесь в том, что хотя 16-битное целое число не может быть больше 65535, оно может быть 65535, а проверка в этой версии — «меньше ли оно 65535».

person mjs    schedule 20.11.2014
comment
Это по-прежнему не учитывает тот факт, что код будет работать по-разному для разных размеров short. - person user694733; 20.11.2014
comment
@user694733 user694733 Верно, хотя размер, скорее всего, только увеличится, и в этом случае проверка все еще сохраняется. - person mjs; 20.11.2014
comment
Да, для больших размеров, но, как уже упоминалось в комментариях к вопросу, для 16-битных это не так. За val = 65538 вы получите val == 2, а не 65535. Если допустимо переполнение, то лучше использовать val &= 0xFFFF. Тогда вы, по крайней мере, получите согласованное поведение между платформами. - person user694733; 20.11.2014
comment
Хм... Хорошая мысль. Оказывается, «неважный код» был важен. См. редактирование вопроса - person mjs; 20.11.2014
comment
Нечего добавить, если вы хотели написать val = ((unsigned short) dbValue) & 0xffff; (с одним &). - person user694733; 20.11.2014

val был объявлен как unsigned short, что обычно (см. примечание) означает 16-битное число без знака (0–65535), поэтому ваш тест никогда не может быть верным, потому что val никогда не может быть больше 2^16- 1 (65535) с этим компилятором и с этой целевой архитектурой.

Использование его как long ничего не изменит. Однако вы можете объявить val как unsigned long.

ИЗМЕНИТЬ

примечание: как справедливо подразумевается в разделе комментариев, точная ширина типов short и int зависит как от компилятора, так и от целевой архитектуры. В Википедии есть раздел, посвященный базовым типам данных C, в котором этот вопрос рассматривается более подробно.

person xbug    schedule 20.11.2014
comment
Кто сказал, что unsigned short должен быть именно 16-битным? - person EOF; 20.11.2014
comment
unsigned int также может быть 16-битным, поэтому я не вижу, как это помогает. - person user694733; 20.11.2014
comment
@EOF: очевидно, это делает его компилятор. Но да, справедливо. - person xbug; 20.11.2014
comment
@xbug Этот компилятор делает. Но эта же кодовая база должна работать на множестве разных целей. - person mjs; 20.11.2014
comment
@mjs: тогда объясните это явно и объявите val как uint16_t. - person xbug; 20.11.2014
comment
Я подумал об этом и вполне мог бы сделать это в будущем. Но эта кодовая база вообще не использует эти типы. Если бы я это написал....... - person mjs; 20.11.2014
comment
Отредактировано, чтобы отразить комментарии. - person xbug; 20.11.2014