Иногда я сталкиваюсь с целочисленным типом (например, целочисленный тип со знаком POSIX off_t
), где было бы полезно иметь макрос для его минимальных и максимальных значений, но я не знаю, как сделать макрос действительно портативный.
Для целых типов без знака я всегда думал, что это просто. 0
для минимума и ~0
для максимума. С тех пор я читал о нескольких различных потоках SO, которые предлагают использовать -1
вместо ~0
для переносимости. Интересная тема с некоторым утверждением здесь:
c ++ - Безопасно ли использовать -1, чтобы установить все биты в true? - Переполнение стека
Однако даже после прочтения этой проблемы я все еще растерялся. Кроме того, я ищу что-то совместимое с C89 и C99, поэтому я не знаю, применяются ли те же методы. Скажем, у меня был тип uint_whatever_t
. Разве я не мог просто привести к 0 сначала, а затем побитово дополнить? Это было бы хорошо?:
#define UINT_WHATEVER_T_MAX ( ~ (uint_whatever_t) 0 )
Типы целых чисел со знаком выглядят так, как будто они будут более крепким орешком. Я видел несколько разных возможных решений, но только one представляется переносимым. Либо это, либо это неправильно. Я нашел это во время поиска в Google для OFF_T_MAX и OFF_T_MIN. Кредит Кристиану Бире:
#define MAX_INT_VAL_STEP(t) \
((t) 1 << (CHAR_BIT * sizeof(t) - 1 - ((t) -1 < 1)))
#define MAX_INT_VAL(t) \
((MAX_INT_VAL_STEP(t) - 1) + MAX_INT_VAL_STEP(t))
#define MIN_INT_VAL(t) \
((t) -MAX_INT_VAL(t) - 1)
[...]
#define OFF_T_MAX MAX_INT_VAL(off_t)
Я не смог найти ничего относительно различных допустимых типов целочисленных представлений со знаком в C89, но в C99 есть замечания по проблемам переносимости целых чисел в §J.3.5:
Представлены ли целочисленные типы со знаком с использованием знака и величины, два
дополнять или дополнять, и является ли необычная ценность ловушкой
представление или обычное значение (6.2.6.2).
Казалось бы, это означает, что могут использоваться только эти три перечисленных числовых представления со знаком. Правильно ли это утверждение и совместимы ли макросы выше со всеми тремя представлениями?
Другие мысли:
Кажется, что подобный функции макрос
MAX_INT_VAL_STEP()
дал бы неверный результат, если бы были биты заполнения. Интересно, есть ли способ обойти это?
Считывание представлений чисел со знаком в Википедии мне приходит в голову, что для всех трех представлений целых чисел со знаком MAX любого типа со знаком со знаком будет:
бит выключен, все биты значений включены (все три)
И его MIN будет либо:
бит знака включен, все биты значения включены (знак и величина)
бит знака включен, все биты значения выключены (дополняются единицами / двумя)
Я думаю, что смог бы проверить знак и величину, выполнив следующее:
#define OFF_T_MIN ( ( ( (off_t)1 | ( ~ (off_t) -1 ) ) != (off_t)1 ) ? /* sign and magnitude minimum value here */ : /* ones and twos complement minimum value here */ )
Тогда, поскольку знак и величина включены в знаковый бит и все биты значения включены, не будет ли минимальный для off_t в этом случае ~ (off_t) 0
? А для минимума, дополняющего единицы / два, мне нужен какой-то способ отключить все биты значения, но оставить бит знака включенным. Не знаю, как это сделать, не зная количества битов значения. Также гарантированно, что знаковый бит всегда будет на один значащий бит больше, чем старший значащий бит?
Спасибо и, пожалуйста, дайте мне знать, если это слишком длинный пост
РЕДАКТИРОВАТЬ 29/12/2010 17:00 EST :
Как сказано ниже в ephemient для получения максимального значения типа без знака, (unsigned type)-1
является более правильным, чем ~0
или даже ~(unsigned type)0
. Из того, что я могу получить, когда вы используете -1, это то же самое, что 0-1, что всегда приведет к максимальному значению в типе без знака.
Кроме того, поскольку может быть определено максимальное значение типа без знака, можно определить, сколько битов значения имеют тип без знака. Благодарим Хальварда Б. Фурусета за его функциональный макрос IMAX_BITS (), который он опубликовал в ответ на вопрос на comp.lang.c
/* Number of bits in inttype_MAX, or in any (1<<b)-1 where 0 <= b < 3E+10 */
#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))
IMAX_BITS (INT_MAX) вычисляет количество бит в int, а IMAX_BITS ((unsigned_type) -1) вычисляет количество бит в unsigned_type. Пока кто-нибудь не реализует 4-гигабайтные целые числа: -)
Однако суть моего вопроса остается без ответа: как определить минимальное и максимальное значения типа со знаком с помощью макроса.Я все еще смотрю на это.Возможно, ответ - нет ответа.
Если вы не просматриваете этот вопрос в StackOverflow, в большинстве случаев вы не сможете увидеть предложенные ответы, пока они не будут приняты.Рекомендуется просмотреть этот вопрос в StackOverflow .