мінімальне та максимальне значення типу даних у C


76

Яка функція визначає мінімальне та максимальне можливе значення типів даних (тобто int, char.etc) у C?

Відповіді:


92

Ви захочете використовувати, limits.hщо надає такі константи (відповідно до зв’язаного посилання):

Де U*_MINпропущено із зрозумілих причин (будь-який тип без підпису має мінімальне значення 0).

Аналогічним чином float.hпередбачені обмеження для floatі doubleтипів:

Ви повинні уважно прочитати статтю floats.h, хоча floatі doubleможете містити встановлені мінімальні та максимальні значення, але точність, з якою кожен тип може представляти дані, може не відповідати тому, що ви намагаєтеся зберегти. Зокрема, важко зберігати винятково великі числа з приєднаними надзвичайно малими фракціями. Отже, float.hнадається ряд інших констант, які допомагають вам визначити, чи a floatчи doublecan, насправді, представляють певне число.


2
яке мінімальне та максимальне значення поплавка?
SuperString

3
SIZE_MAX(максимальний розмір a size_t) - ще один корисний.
кафе

size_t maxSize = SIZE_MAX;
Joey van Hummel

@MartinBeckett не відповідно до файлу заголовка, або моїх спогадів про написання цього на C? FLT_MIN приблизно дорівнює нулю, ні?
Адам

Проголосувати проти, тому що відповідь - просто - неправильна. Запитання задає мінімальне та максимальне значення, а файл заголовка містить лише відповідь на максимальне значення. Потрібно розрахувати мінімальне значення (із задоволенням зміню свій голос, якщо хтось прийде і виправить мене, але я розумію / пам’ятаю, що це згідно з коментарем @ JohnMudd). "FLT_MIN = мінімальне значення поплавка", як написано у цій відповіді, абсолютно НЕПРАВИЛЬНО.
Адам

33

"Але гліф", я чую, як ви запитуєте, "що, якщо мені доведеться визначити максимальне значення для непрозорого типу, максимум якого з часом може змінитися?" Ви можете продовжити: "Що робити, якщо це typedef у бібліотеці, яку я не контролюю?"

Я радий, що ви запитали, тому що я просто витратив пару годин, готуючи розчин (який потім мені довелося викинути, бо це не вирішило моєї фактичної проблеми).

Ви можете використовувати цей зручний maxofмакрос для визначення розміру будь-якого допустимого цілочисельного типу.

Ви можете використовувати його так:

Якщо ви хочете, ви можете кинути '(t)' на передню частину цих макросів, щоб вони дали вам результат типу, про який ви запитуєте, і вам не потрібно робити кастинг, щоб уникнути попереджень.


Чи не буде ~((t) 0)працювати максимум без підпису? (це не так, але я ще не впевнений, чому).
Готьє

Дякуємо за інформацію щодо виявлення підписів. Я оновлю відповідь.
Гліф

1
Натомість усі ці константи 8ULL, мабуть, мають бути CHAR_BIT.
jschultz410

umaxof (t) можна набагато легше записати як ((t) -1) або (~ (t) 0), які обидва гарантовано працюють за стандартом C. smaxof (t) можна записати ((t) ~ (1ULL << (sizeof (t) * CHARBIT - 1))). Підписані мінімуми набагато складніші.
jschultz410

Великі пальці вгору на maxof умовно, використовуючи правильний макрос залежно від підписаного!
jschultz410

7

Максимальне значення будь-якого непідписаного інтегрального типу:

  • ((t)~(t)0) // Загальний вираз, який би працював майже за всіх обставин.

  • (~(t)0)// Якщо ви знаєте, що ваш тип tмає однаковий або більший розмір, ніж unsigned int. (Цей привід змушує просувати тип.)

  • ((t)~0U)// Якщо ви знаєте, що ваш тип tмає менший розмір, ніж unsigned int. (Цей тип пониженого статусу після оцінки unsigned intвиразу -type ~0Uоцінюється.)

Максимальне значення будь-якого підписаного інтегрального типу:

  • Якщо у вас є непідписаний варіант типу t, ((t)(((unsigned t)~(unsigned t)0)>>1))це дасть вам найшвидший результат, який вам потрібен.

  • В іншому випадку використовуйте це (дякую @ vinc17 за пропозицію): (((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)

Мінімальне значення будь-якого підписаного інтегрального типу:

Ви повинні знати поданий номер машини з підписом. У більшості машин використовується доповнення 2, і це -(((1ULL<<(sizeof(t)*CHAR_BIT-2))-1)*2+1)-1буде працювати для вас.

Щоб визначити, чи використовує ваша машина доповнення 2, визначте (~(t)0U)і (t)(-1)представляйте те саме.

Отже, у поєднанні з вищезазначеним:

дасть вам мінімальне значення будь-якого підписаного інтегрального типу.

Як приклад: Максимальне значення size_t(воно ж SIZE_MAXмакрос) можна визначити як (~(size_t)0). Вихідний код ядра Linux визначає SIZE_MAXмакрос таким чином.

Однак одне застереження : усі ці вирази використовують або кастинг типу, або sizeofоператор, і тому жодне з них не буде працювати в умовних умовах попереднього процесора ( #if... #elif... #endifтощо).

(Відповідь оновлено за включення пропозицій від @chux та @ vinc17. Дякую вам обом.)


Зверніть увагу, що це unsigned long longможе бути не найбільший цілочисельний тип; uintmax_tмає бути кращим, але навіть не завжди є найбільшим цілочисельним типом на практиці (див. GCC __int128). У своїй відповіді я дав більш портативне рішення для максимальної кількості підписаних типів. Тоді з нього можна було б вивести мінімум, як і ви. Що стосується умов попереднього процесора, sizeofїх також не можна використовувати, оскільки попередня обробка відбувається перед семантичним аналізом, тобто препроцесор не має поняття типів.
vinc17

Метод "Максимальне значення будь-якого підписаного інтегрального типу" тут спирається на припущення, хоча і дуже поширені. Зверніть увагу, що, хоча це незвичайне явище, xxx_MAX == Uxxx_MAXце дозволено в C, а також xxx_MAX < Uxxx_MAX/2. Зазначено те, що xxx_MAX <= Uxxx_MAXобидва типи мають однаковий розмір.
chux

@chux З того, що я знав на сьогоднішній день, charце єдиний тип стандарту C, який, можливо xxx_MAX == Uxxx_MAX, charможе задовольнити , оскільки може бути підписаним або непідписаним залежно від реалізації. І для xxx_MAX < Uxxx_MAX/2випадку це, найімовірніше, буде спричинено арифметикою доповнення не-2 (інакше це не матиме сенсу для реалізації).
Explorer09

1
~((t) 0)не працює, коли (t)0вужче, ніж int.
chux

1
@chux Дякую за підказку про ~((t) 0). Що стосується випадків xxx_MAX == Uxxx_MAXand xxx_MAX < Uxxx_MAX/2, з того, що я прочитав у стандарті C99, так, вони дозволені.
Explorer09,

4

Ми можемо просто отримати найбільше значення непідписаного типу даних і відняти його від максимального значення, щоб отримати мінімальне значення.
Аканьш

1
Це чудова, незалежна від системи відповідь, яка демонструє розуміння типів, пам'яті та, звичайно, побітових операторів C.
Джонатан Комар,

@JonathanKomar Усі вищезазначені мінімуми підписують архітектуру доповнення 2, що зазвичай - але не завжди - має місце в C.
jschultz410,

Виправлення: залежно від системи (передбачає інтерпретацію бітів доповнення 2) Дякую jschultz410.
Джонатан Комар,


3

Я написав кілька макросів, які повертають мінімальний і максимальний значення будь-якого типу, незалежно від підпису:

Приклад коду:


3

Заголовний файл limits.hвизначає макроси, які розширюються до різних меж та параметрів стандартних цілочисельних типів.


яке мінімальне значення символу без знака?
SuperString

4
@Superstring, мінімальне значення для будь-якого непідписаного типу - 0.
Mark Elliot

4
Я хочу негативні значення без знака! :-)
Alok Singhal

2

Щоб отримати максимальне значення цілочисельного типу без підпису t , ширина якого по крайней мере, один з unsigned int( в іншому випадку кожен отримує проблеми з цілими заохоченнями): ~(t) 0. Якщо один хоче також підтримувати більш короткі тип, можна додати ще один кидок: (t) ~(t) 0.

Якщо цілочисельний тип tпідписаний, припускаючи, що немає бітів доповнення, можна використовувати:

Перевага цієї формули полягає в тому, що вона не базується на якійсь непідписаній версії t (або більшого типу), яка може бути невідомою або недоступною (навіть uintmax_tможе бути недостатньою при нестандартних розширеннях). Приклад із 6 бітами (на практиці неможливо, лише для читабельності):

У доповненні двох мінімальне значення протилежне максимальному значенню, мінус 1 (в інших цілочисельних поданнях, дозволених стандартом ISO C, це якраз протилежне максимальному значенню).

Примітка: Щоб виявити підпис, щоб вирішити, яку версію використовувати: (t) -1 < 0буде працювати з будь-яким цілочисельним представленням, даючи 1 (true) для підписаних цілих типів і 0 (false) для цілих беззнакових типів. Таким чином, можна використовувати:


Для підписаного макс., Чому б не простіше (~ ((t) 1 << (sizeof (t) * CHAR_BIT - 1)))?
jschultz410

1
@ jschultz410 Оскільки це невизначена поведінка. Математичне (і позитивне) значення 2 до sizeof(t) * CHAR_BIT - 1неможливо представити у підписаному типі t. Ви припускаєте поведінку "загортання" лівого зсуву, яка не є стандартною (і може не вдатися при оптимізації компіляторів) і навіть не матиме сенсу в цілочисельних поданнях, відмінних від доповнення двох (як це дозволено стандартом С).
vinc17

0

Значення MIN та MAX будь-якого цілочисельного типу даних можуть бути обчислені без використання будь-яких бібліотечних функцій, як показано нижче, і та сама логіка може бути застосована до інших цілочисельних типів short, int та long.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.