Как переносить проверку экстремальных значений для типов данных SuSv3?

По SuSv3, ssize_t должен быть целочисленным типом со знаком. Если я хочу проверить, больше ли вычисляемое мной значение, чем максимально допустимое значение для такого типа данных, я могу сравнить его с INT_MAXчто не приятно.

Есть ли более переносимый способ, которым это сравнение может быть сделано — макрос / функция f это работает как в

 f(<typedef'ed datatype>) = {maximum value allowed for <TDDT> on this system)?

, или короткая последовательность таких операций того же рода?

система:
Ubuntu 12.04.
glibc 2.15
Ядро 3.2.0

P.S .: При поиске в Google, я сначала подумал, что расширение gcc ‘typeof’ звучит многообещающе; но это, казалось, не помогло здесь (или делает это?). Это значит, что я в порядке со всем, что может быть расширением / атрибутом gcc / и т.д.

1

Решение

Для беззнакового арифметического типа (type)-1 это максимальное значение. Поскольку вы не знаете, каков относительный размер типов, приведите к uintmax_t:

#define UNSIGNED_TYPE_MAX(t) ((uintmax_t)(t)-1)
if ((uintmax_t)x > UNSIGNED_TYPE_MAX(size_t)) puts("too large");

Для подписанных типов такого ярлыка нет. На самом деле, я не думаю, что есть какой-либо способ определения наибольшего значения типа со знаком в строго переносимом C89 или C99, без использования соответствующей константы, такой как SSIZE_MAX за ssize_t, C99 определяет константы для каждого типа, предназначенного для арифметики, определенной в stdint.h для типов, определенных в ISO C. Для типов, определенных в POSIX, но не в стандартном C, существует много значений в limits.h; обратите внимание, что они являются пределом допустимых значений для того, для чего предназначен тип, а не пределом того, что может вписываться в тип. Например, если size_t это 32-битный тип, то SIZE_MAX гарантированно будет 232-1, тогда как SSIZE_MAX может быть меньше 231-1, если реализация не поддерживает число байтов больше этого.

С дополнительным предположением, что целые числа представлены в двоичном коде и нет битов заполнения, что безопасно, если вы ограничиваете себя POSIX (где CHAR_BIT является всегда 8), вы можете определить максимальное значение, рассчитав размер типа: в знаковом типе есть один знаковый бит, а все остальное — бит значения.

#define SIGNED_TYPE_MAX(t) (((uintmax_t)1 << (sizeof(t) * CHAR_BIT - 1)) - 1)

Обратите внимание, что такие вещи, как «удвоение, пока оно не перестанет расти» или «пуш в битовой комбинации 0111… 111» являются хитрыми. Стандарт C говорит, что поведение для типов со знаком не определено, и GCC использует это для оптимизации операций над типами со знаком, что может привести к неверному значению в случае переполнения. Например, он может выполнять вычисления в регистре большего размера, так что переполнение оказывается невозможным.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]