Является ли максимальное значение размера t (SIZE MAX) определенным относительно других целочисленных типов?
я пишу библиотеку функций, которые будут безопасно конвертировать между различными числовыми типами или умереть, пытаясь. Мое намерение-примерно равные части create-useful-library и learn-c-edge-cases.
мой int
- to -size_t
функция вызывает GCC -Wtype-limits
предупреждение, что утверждает, что я не должен проверять, если int
больше SIZE_MAX
, потому что это никогда не будет правдой.
(Еще одна функция, которая преобразует int
to ssize_t
выдает идентичное предупреждение о SSIZE_MAX
.)
мой MCVE, с дополнительными комментариями и детскими шагами, является:
#include <stdint.h> /* SIZE_MAX */
#include <stdlib.h> /* exit EXIT_FAILURE size_t */
extern size_t i2st(int value) {
if (value < 0) {
exit(EXIT_FAILURE);
}
// Safe to cast --- not too small.
unsigned int const u_value = (unsigned int) value;
if (u_value > SIZE_MAX) { /* Line 10 */
exit(EXIT_FAILURE);
}
// Safe to cast --- not too big.
return (size_t) u_value;
}
Предупреждения Компилятора
я получаю аналогичные предупреждения от GCC 4.4.5 в Linux 2.6.34:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o math_utils.o math_utils.c
math_utils.c: In function ‘i2st’:
math_utils.c:10: warning: comparison is always false due to limited range of data type
...а также из GCC 4.8.5 на Linux 3.10.0:
math_utils.c: In function ‘i2st’:
math_utils.c:10:5: warning: comparison is always false due to limited range of data type [-Wtype-limits]
if (u_value > SIZE_MAX) { /* Line 10 */
^
эти предупреждения не кажутся мне оправданными, по крайней мере, в общем случае. (Я не отрицаю, что сравнение может быть - всегда ложь." на некотором определенном сочетании оборудования и компилятор.)
Стандарт C
стандарт c 1999, по-видимому, не исключает int
больше SIZE_MAX
.
sizeof
оператор"
не обращается size_t
вообще, за исключением описания его как
- определено в <stddef.h>
(и другие заголовки)".
"7.17 Общие определения <stddef.h>
"
определяет size_t
as
"целочисленный тип без знака результата sizeof
оператора".
(Благодаря, ребята!)
"7.18.3 пределы других целочисленных типов"
более полезно ---
это определяет
"предел size_t
" as:
SIZE_MAX
65535
...смысл SIZE_MAX
может быть маленький as 65535.
Ан int
(signed или unsigned)
может быть намного больше, в зависимости от оборудования и компилятора.
Переполнение Стека
принятый ответ на
"unsigned int
и size_t
"
кажется, поддерживает мою интерпретацию
(Курсив мой):
на
size_t
тип может быть больше, равен, или меньше anunsigned int
и ваш компилятор может делать предположения о его оптимизации.
этот ответ приводит то же самое Раздел "7.17" из стандарта C, который я уже цитировал.
Другие Документы
мои поиски обнаружили документ открытой группы "сведения Нейтральность размера и 64-разрядная поддержка", какие претензии "64-битные модели данных " (Курсив мой):
ISO / IEC 9899: 1990, языки программирования-C (ISO C) оставил определение
short int
наint
наlong int
иpointer
намеренно расплывчатым [...] Единственным ограничением было то, чтоint
s должно быть не меньшеshort
S иlong
s должно быть не меньшеint
S иsize_t
должен представлять самый большой тип без знака поддерживается реализацией. [...] Связь между основными типами данных может быть выражена следующим образом:
sizeof(char)
sizeof(short) sizeof(int)sizeof(long)
=sizeof(size_t)
если это правда, то испытания int
против SIZE_MAX
действительно бесполезно...
но эта статья не цитирует главы и стихи, поэтому я не могу сказать, как ее авторы пришли к своему выводу.
Собственный
"Базовая Спецификация Версия 7"
sys/types.h
docs
не обращайся к этому в любом случае.
У Меня Вопрос
я понимаю, что size_t
вряд ли будет уже, чем int
, а гарантирует ли стандарт C сравнение some_unsigned_int > SIZE_MAX
будет всегда быть ложным?
Если да, то где?
Не-Дубликатов
есть два полу-дубликата этого вопроса, но они оба задают более общие вопросы о том, что size_t
предполагается представлять и когда он должен / не должен использоваться.
"что это
size_t
в C?" не затрагивает отношения междуsize_t
и другие целочисленные типы. Его принятый ответ - это просто цитата из Википедии, которая не предоставляет никакой информации за пределами того, что я уже нашел."каково правильное определение
size_t
?" начинается почти дубликат моего вопрос, но затем отклоняется от курса, задавая когдаsize_t
следует использовать и почему он был введен. Он был закрыт как дубликат предыдущего вопроса.
3 ответов
текущий стандарт C не требует size_t
чтобы быть по крайней мере таким же широким, как int
, а я скептически отношусь к любой версии стандарта когда-либо делал так. size_t
необходимо иметь возможность представлять любое число, которое может быть размером объекта; если реализация ограничивает размеры объекта шириной 24 бита, то size_t
может быть 24-битным типом без знака, независимо от того, что int
есть.
предупреждение GCC не относится к теоретическим возможностям. Это проверка конкретная аппаратная платформа и конкретный компилятор и среда выполнения. Это означает, что иногда он запускает код, который пытается быть портативным. (Есть и другие случаи, когда портативный код вызовет дополнительные предупреждения GCC.) Это может быть не то, что вы надеялись сделать предупреждение, но, вероятно, есть пользователи, ожидания которых точно соответствуют реализованному поведению, и стандарт не содержит никаких рекомендаций для предупреждений компилятора.
As OP упоминает в комментарии, есть долгая история, связанная с этим предупреждением. Предупреждение было введено в версии 3.3.2 или около того (в 2003 году), по-видимому, не контролируется any -W
флаг. Об этом сообщалось как ошибка 12963 пользователем, который, очевидно, чувствовал, как и вы, что предупреждение препятствует портативному программированию. Как видно из отчета об ошибке, различные сопровождающие GCC (и другие известные члены сообщества) взвешивали с сильно ощущаемыми, но противоречивыми мнениями. (Это общая динамика в отчетах об ошибках с открытым исходным кодом.) Через несколько лет было принято решение контролировать предупреждения с флагом и не включать этот флаг по умолчанию или как часть -Wall
. Тем временем, была переименована в -Wextra
и вновь созданного флага (-Wtype-limits
) был добавлен к -Wextra
коллекция. Мне кажется, это правильное решение.
остальная часть этого ответа содержит мой личный мнение.
-Wall
, как описано в руководстве GCC, фактически не включает все предупреждения. Это позволяет предупреждать " о конструкциях, которые некоторые пользователи считают сомнительными, и которые легко избежать (или изменить, чтобы предотвратить предупреждение), даже в сочетании с макросами."Существует ряд других условий, которые GCC может обнаружить:
обратите внимание, что некоторые предупреждающие флаги не подразумевается
-Wall
. Некоторые из них предупреждают конструкции, которые пользователи обычно не считают сомнительными, но которые иногда вы можете проверить; другие предупреждают о конструкциях, которые необходимы или трудно избежать в некоторых случаях, и нет простого способа изменить код, чтобы подавить предупреждение. Некоторые из них включены с помощью-Wextra
но многие из них должны быть включены по отдельности.
эти различия несколько произвольны. Например, я должен стискивать зубы каждый раз, когда GCC решает "предлагаю скобки вокруг ‘&&’ в ‘||’". (Похоже, он не чувствует необходимости предлагать круглые скобки вокруг * внутри+, что для меня не отличается.) Но я признаю, что у всех нас разные уровни комфорта с приоритетом оператора, и не все предложения GCC о скобках кажутся мне чрезмерными.
но в целом, различие кажется разумным. Существуют предупреждения, которые обычно применимы, и они включены с помощью -Wall
, который должен всегда быть указанным, потому что эти предупреждения почти всегда требуют действий для исправления дефицита. Есть и другие предупреждения, которые могут быть полезны в определенных обстоятельствах, но которые также имеют много ложноположительных; эти предупреждения необходимо исследовать индивидуально, потому что они не всегда (или даже часто) соответствуют проблеме в вашем коде.
я знаю, что есть люди, которые считают, что простой факт, что GCC знает, как предупредить о каком-то условии достаточно, чтобы потребовать действий, чтобы избежать этого предупреждения. Каждый имеет право на свои стилистические и эстетические суждения, и это правильно и справедливо, что такие программисты добавляют -Wextra
для их флагов сборки. Однако я не в этой толпе. В данный момент в проекте я попробую построить с большой коллекцией дополнительных предупреждений и рассмотрю, следует ли изменять мой код на основе отчетов, но я действительно не хочу тратить время на разработку, думая о не-проблемах каждый раз пора восстановить файл. The -Wtypes-limit
флаг попадает в эту категорию для меня.
ничего не требует максимум size_t
больше int
. Такие архитектуры где SIZE_MAX
is INT_MAX редки, хотя и я сомневаюсь, что GCC поддержит любой из них.
что касается исправить, вы можете использовать #if
:
#if INT_MAX > SIZE_MAX
if (u_value > SIZE_MAX) { /* Line 10 */
exit(EXIT_FAILURE);
}
#endif
Я согласен с Ремо.Д толкование.
size_t
указывается как стандартное целое число без знака, но стандарт не ограничивает его размер относительно любого из них, кроме как говоря, что он должен иметь возможность удерживать по крайней мере 65535
.
он может быть меньше, равен или больше по размеру, чем unsigned int
.