Тестирование на максимальное значение без знака - PullRequest
4 голосов
/ 27 декабря 2010

Это правильный способ проверки максимального значения без знака в коде C и C ++:

if(foo == -1)
{
    // at max possible value
}

, где foo - это unsigned int, unsigned short и т. Д.

Ответы [ 6 ]

12 голосов
/ 27 декабря 2010

Для C ++, я думаю, вам лучше использовать шаблон numeric_limits из заголовка <limits>:

if (foo == std::numeric_limits<unsigned int>::max())
    /* ... */

Для C другие уже указали заголовок <limits.h> и UINT_MAX.


Очевидно, что "решения, которым разрешено называть тип, просты", поэтому вы можете иметь:

template<class T>
inline bool is_max_value(const T t)
{
    return t == std::numeric_limits<T>::max();
}

[...]

if (is_max_value(foo))
    /* ... */
5 голосов
/ 27 декабря 2010

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

Для C ваш подход является правильным только для типов с рейтингом конверсии int или выше. Это связано с тем, что перед сравнением значение unsigned short, например, сначала преобразуется в int, если все значения подходят, или в unsigned int в противном случае. Тогда ваше значение foo будет сравниваться либо с -1, либо с UINT_MAX, а не с тем, что вы ожидаете.

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

С расширением typeof в gcc это легко возможно. Вам просто нужно сделать что-то вроде

if (foo == (typeof(foo))-1)
2 голосов
/ 27 декабря 2010

Как уже отмечалось, вам, вероятно, следует использовать if (foo == std::numeric_limits<unsigned int>::max()) для получения значения.

Однако для полноты в C ++ -1 «вероятно» гарантированно будет максимальным значением без знака при преобразовании в без знака (это не было бы так, если бы в верхнем конце диапазона значений без знака были неиспользуемые битовые комбинации) ).

См. 4.7 / 2:

Если тип назначения не подписан, полученное значение наименьшее целое число без знака соответствует целое число источника (по модулю 2 ^ n, где n это количество битов, используемых для представляют тип без знака). [Заметка: В дополнительном представлении двух это преобразование является концептуальным и нет изменений в битовой структуре (если нет усечения). ]

Обратите внимание, что специально для случая unsigned int из-за правил в 5/9 представляется, что если один из операндов не подписан, другой будет автоматически преобразован в беззнаковый, так что вам даже не нужно приводить -1 (если я правильно читаю стандарт). В случае короткого знака без знака вам понадобится прямая проверка или явное приведение из-за автоматического интегрального повышения, вызванного ==.

1 голос
/ 27 декабря 2010

используя #include <limits.h> вы можете просто сделать

if(foo == UINT_MAX)

если foo является unsigned int, то оно имеет значение [0 - +4,294,967,295] (если 32-битное)

Подробнее: http://en.wikipedia.org/wiki/Limits.h

редактировать: в C

если вы делаете

#include <limits.h>
#include <stdio.h>

int main() {
    unsigned int x = -1;
    printf("%u",x);
    return 0;
}

вы получите результат 4294967295 (в 32-битной системе), и это потому, что внутренне -1 представлен 11111111111111111111111111111111 в дополнении к двум. Но поскольку это unsigned, теперь нет «знакового бита», поэтому он работает в диапазоне [0-2 ^ n]

Также см .: http://en.wikipedia.org/wiki/Two%27s_complement

См. Ответы других для C++ части std::numeric_limits<unsigned int>::max()

0 голосов
/ 28 декабря 2010

Вот попытка сделать это в C. Это зависит от реализации, не имеющей битов заполнения:

#define IS_MAX_UNSIGNED(x) ( (sizeof(x)>=sizeof(int)) ? ((x)==-1) : \
                             ((x)==(1<<CHAR_BIT*sizeof(x))-1) )

Или, если вы можете изменить переменную, просто сделайте что-то вроде:

if (!(x++,x--)) { /* x is at max possible value */ }

Редактировать: И если вас не волнуют возможные расширенные целочисленные типы, определенные реализацией:

#define IS_MAX_UNSIGNED(x) ( (sizeof(x)>=sizeof(int)) ? ((x)==-1) : \
                             (sizeof(x)==sizeof(short)) ? ((x)==USHRT_MAX) : \
                             (sizeof(x)==1 ? ((x)==UCHAR_MAX) : 42 )

Конечно, вы можете использовать sizeof(char) в последней строке, но я считаю, что это запах кода и обычно ловит его на запах кода, поэтому я просто написал 1. Конечно, вы также можете просто полностью удалить последнее условие.

0 голосов
/ 27 декабря 2010

Я бы определил константу, которая будет содержать максимальное значение, необходимое для разработки вашего кода. Использование «-1» сбивает с толку. Представьте, что кто-то в будущем изменит тип с unsigned int на int, это испортит ваш код.

...