быть в состоянии держать 65535. Это было впервые указано в C99.

у библиотеку функций, которые будут безопасно конвертировать между различными числовыми типами или умирать, пытаясь. Мое намерение примерно равно частям create-полезным-library и learn-C-edge-case.

мойint-До-size_t функция запускает GCC-Wtype-limits предупреждение, что утверждает, что я не должен проверять, еслиint больше, чемSIZE_MAXпотому что это никогда не будет правдой. (Еще одна функция, которая преобразуетint в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 1999 года не исключаетint быть больше чемSIZE_MAX.

Раздел "6.5.3.4sizeof оператор "не обращаетсяsize_t вообще, кроме как описать это как<stddef.h> (и другие заголовки) ".

Раздел «7.17 Общие определения<stddef.h>"определяетsize_t как "целочисленный тип без знака результатаsizeof оператор ". (Спасибо, ребята!)

Раздел «7.18.3 Пределы других целочисленных типов» более полезен - он определяет «пределsize_t" как:

SIZE_MAX 65535

...смыслSIZE_MAX может быть какнебольшой как 65535. Anint (подписанный или неподписанный) может быть намного больше, в зависимости от оборудования и компилятора.

Переполнение стека

Принятый ответ на "unsigned int противsize_t«Кажется, поддерживает мою интерпретацию (выделение добавлено):

size_t тип может быть больше, чем, равноили меньше чем unsigned intи ваш компилятор может сделать предположения об этом для оптимизации.

В этом ответе цитируется тот же «Раздел 7.17» стандарта Си, который я уже цитировал.

Другие документы

Мои поиски обнаружили документ Open Group "Нейтральность размера данных и 64-битная поддержка", которая заявляет в разделе" 64-битные модели данных "(выделение добавлено):

ISO / IEC 9899: 1990, Языки программирования - C (ISO C) оставил определениеshort int,int,long intиpointer намеренно расплывчатые [...] единственными ограничениями было то, чтоints должно быть не меньше чемshortс иlongs должно быть не меньше чемintс иsize_t должен представлять самый большой неподписанный тип, поддерживаемый реализацией, [...] Отношение между основными типами данных может быть выражено как:

sizeof(char) <=sizeof(short) <=sizeof(int) <=sizeof(long) = sizeof(size_t)

Если это правда, то тестированиеint противSIZE_MAX действительно бесполезно ... но в этой статье не приводятся главы и стихи, поэтому я не могу сказать, как ее авторы пришли к своему заключению. Их собственная "Базовая спецификация версии 7"sys/types.h документы не обращайтесь к этому так или иначе.

Мой вопрос

Я это понимаюsize_t вряд ли будет ужеint, ностандартная гарантия C это сравнениеsome_unsigned_int > SIZE_MAX будемвсегда быть ложным? Если так, то где?

Не-Дубликаты

Есть два полудубликата этого вопроса, но они оба задают более общие вопросы о том, чтоsize_t должен представлять и когда он должен / не должен использоваться.

"Что такоеsize_t в С?«не затрагивает отношения междуsize_t и другие целочисленные типы. Его принятый ответ - просто цитата из Википедии, которая не предоставляет никакой информации, кроме той, которую я уже нашел.

"Какое правильное определениеsize_t?"начинает почти дубликат моего вопроса, но затем отклоняется от курса, спрашивая, когдаsize_t следует использовать и почему это было введено. Он был закрыт как дубликат предыдущего вопроса.

 M.M01 окт. 2017 г., 16:32
Ваше утверждение "size_t должно представлять самый большой неподписанный тип, поддерживаемый реализацией". ложно У C90 такого требования не было, иsizeof(size_t) < sizeof(int) было возможно
 Kevin J. Chase01 окт. 2017 г., 17:07
@ М.М .: Не вините меня --- я цитировалОткрытая группах "Нейтральность размера данных и 64-битная поддержкаMsgstr "Мое ожидание было противоположным, и именно так я сгенерировал это (поддельное) предупреждение компилятора.

Ответы на вопрос(3)

Интерпретация Remo.D.

size_t определено как стандартное целое число без знака, но стандарт не ограничивает его размер относительно любого из них, за исключением того, что он должен содержать как минимум65535.

Поэтому он может быть меньше, равен или больше по размеру, чемunsigned int.

 M.M01 окт. 2017 г., 16:36
С89 не требуетсяsize_t быть в состоянии держать 65535. Это было впервые указано в C99.
 Kevin J. Chase01 окт. 2017 г., 06:00
Я полагаю, что мое замешательство отчасти связано с тем, что этот высоко голосованный ответ прямо противоречитОткрытая группа что я процитировал (и очевидное намерение предупреждения GCC). Я неправильно читаю одну из них, или эта газета совершенно не права по этому поводу?
 rici01 окт. 2017 г., 06:59
@kevin: если вы посмотрите в Интернете достаточно долго, вы найдете что-то, что довольно хорошо подтверждает любую ошибку, независимо от того, насколько вопиющей. Ошибки не обязательно являются преднамеренной ложью или второстепенными заблуждениями. Иногда они просто опечатки. Иногда это вещи, которые когда-то были фактическими, но 30 лет спустя имеют мало отношения к реальности. Иногда они являются архивами невинных ошибок, которые никогда не были предназначены для сохранения. Это сбивает с толку, когда очевидная ошибка подписана кем-то заслуживающим доверия, но это случается.

size_t быть больше чемint, Такие архитектуры, гдеSIZE_MAX это <=INT_MAX хотя редко, и я сомневаюсь, что GCC поддержитЛюбые из них.

Дляфиксировать, вы можете использовать#if:

#if INT_MAX > SIZE_MAX
if (u_value > SIZE_MAX) {  /* Line 10 */
    exit(EXIT_FAILURE);
}
#endif
 Antti Haapala01 окт. 2017 г., 17:41
@rici нет, это не так.size_t никогда не может быть того же типа, что иint.
 rici01 окт. 2017 г., 22:21
Clang не предупреждает, если вы пишетеif (INT_MAX > SIZE_MAX && u_value > SIZE_MAX), но большинство версий GCC делают.
 Joshua23 авг. 2018 г., 17:51
Есть порт gcc для процессора параллакса. Максимальный размер выделения составляет 32 КБ, поэтому size_t действительно может быть коротким целым числом.
Решение Вопроса

size_t быть по крайней мере такой же ширины, какintи я скептически отношусь к любой версии стандарта, которая когда-либо делала это.size_t должен иметь возможность представлять любое число, которое может быть размером с объект; если реализация ограничивает размеры объекта шириной 24 бита, тоsize_t может быть 24-битным беззнаковым типом, независимо от того, чтоint является.

Предупреждение GCC не относится к теоретическим возможностям. Это проверка конкретной аппаратной платформы, определенного компилятора и среды выполнения. Это означает, что иногда он запускается в коде, который пытается быть переносимым. (Есть и другие случаи, когда переносимый код будет вызывать необязательные предупреждения GCC.) Возможно, это не то, на что вы надеялись, что это предупреждение сработает, но, вероятно, есть пользователи, чьи ожидания точно соответствуют реализованному поведению, и стандарт не дает никаких указаний вообще. для предупреждений компилятора.

Как упоминает OP в комментарии, существует длинная история, связанная с этим предупреждением. Предупреждение было введено в версии 3.3.2 или около того (в 2003 году), очевидно, не контролируется какими-либо-W флаг. Это было сообщено какошибка 12963 пользователем, который, очевидно, почувствовал, как и вы, что предупреждение препятствует переносу программ. Как видно из отчета об ошибках, различные сопровождающие GCC (и другие известные члены сообщества) высказывали свои мнения с сильным, но противоречивым мнением. (Это обычная динамика в отчетах об ошибках с открытым исходным кодом.) Через несколько лет было принято решение контролировать предупреждения с помощью флага и не включать этот флаг по умолчанию или как часть-Wall, Тем временем-W вариант был переименован-Wextraи вновь созданный флаг (-Wtype-limits) был добавлен в-Wextra коллекция. Мне кажется, это правильное решение.

Остальная часть этого ответа содержит мое личное мнение.

-Wallкак указано в руководстве GCC, на самом деле не позволяетвсе предупреждения. Он включает эти предупреждения «о конструкциях, которые некоторые пользователи считают сомнительными и которые легко избежать (или изменить, чтобы предотвратить предупреждение), даже в сочетании с макросами». Существует ряд других условий, которые GCC может обнаружить:

Обратите внимание, что некоторые флаги предупреждения не подразумеваются-Wall, Некоторые из них предупреждают о конструкциях, которые пользователи обычно не считают сомнительными, но которые вы иногда можете проверить; другие предупреждают о конструкциях, которые в некоторых случаях необходимо или трудно избежать, и не существует простого способа изменить код для подавления предупреждения. Некоторые из них включены-Wextra но многие из них должны быть включены по отдельности.

Эти различия несколько произвольны. Например, мне приходится стискивать зубы каждый раз, когда GCC решает «предложить скобки вокруг around &&’ в пределах ‘||’ ». (Кажется, нет необходимости предлагать скобки вокруг «*» в пределах «+», что для меня не отличается). Но я признаю, что у всех нас разные уровни комфорта с приоритетом оператора, и не у всех предложения GCC о скобках кажутся мне чрезмерными.

Но в целом различие кажется разумным. Есть предупреждения, которые обычно применимы, и те, которые включены с-Wall, который долженвсегда быть уточненным, потому что эти предупреждения почти всегда требуют действий для устранения недостатка. Существуют и другие предупреждения, которые могут быть полезны в определенных обстоятельствах, но также содержат много ложных срабатываний; эти предупреждения необходимо изучать индивидуально, потому что они не всегда (или даже часто) соответствуют проблеме в вашем коде.

Я знаю, что есть люди, которые чувствуют, что сам факт того, что GCC знает, как предупредить о каком-либо условии, является достаточным, чтобы требовать действий, чтобы избежать этого предупреждения. Каждый имеет право на свои стилистические и эстетические суждения, и это правильно, и именно такие программисты добавляют-Wextra их строить флаги. Я не в этой толпе, однако. На данном этапе проекта я попробую сборку с включенной большой коллекцией необязательных предупреждений и рассмотрю вопрос о том, стоит ли изменять мой код на основе отчетов, но я действительно не хочу тратить время на разработку думать о проблемах каждый раз, когда я перестраиваю файл.-Wtypes-limit флаг попадает в эту категорию для меня.

 rici01 окт. 2017 г., 15:37
@kevin: стандарт C представляет собой набортребования, Как правило, это неразрешать или жезапрещать все, кроме того, что оно (неявно) допускает все, что совместимо с требованиями, и (неявно) запрещает все, что делает невозможным выполнение требований. Заявление о том, что стандарт не требуетX Мне кажется, это самый точный способ уловить намерение, поскольку оно не основано на дедукции. Я прошу прощения, если эта привычка усложнила ваш анализ.
 Kevin J. Chase01 окт. 2017 г., 14:43
@ machine_1: Мое чтение этого было "Текущий стандарт C не запрещаетsize_t быть уже, чемint, ... ". Но я согласен, разбор этого потребовал некоторых усилий.
 Kevin J. Chase01 окт. 2017 г., 06:30
Я собирался попросить вас процитировать это утверждение о предупреждении GCC, но я думаю,я нашел это, (Похоже, я был не единственным разочарован предупреждением, которое, по сути, говорит вам сделать ваш кодМеньше в соответствии с разрешением этой ошибки, когда-то в 2007 году GCC 4.3 собирал эти предупреждения в новом-Wtype-limits вариант. Поэтому я полагаю, что решение заключается в использовании-Wno-type-limits всякий раз, когда я использую-Wextra, (И мойMakefile растет еще один комментарий размером с абзац только для поддержания моего здравомыслия ...)
 rici01 окт. 2017 г., 15:32
@ machine_1: "шире" и "не уже"значит разные вещи, Вы не можете изменить>= в> без изменения семантики программы. Во всяком случае, я изменил его на «по крайней мере, такой же ширины, как», что мне кажется довольно распространенным, но, возможно, лучше соответствует эстетике читателей ответа.
 machine_101 окт. 2017 г., 16:49
@rici Да, фраза «по крайней мере такой же ширины, как» - это правильный перевод.

Ваш ответ на вопрос