Стандарт C в отношении размера переполнения size_t

Это неопределенное поведение? Соответствующие части стандарта мало что говорят.

size_t n = SIZE_MAX / sizeof(double) + 1;
size_t m = sizeof(double[n]);

person ov2k    schedule 03.09.2019    source источник
comment
Я бы отнесся к этому как к неопределенному упущению   -  person M.M    schedule 03.09.2019
comment
Если это не определено стандартом, то это буквально неопределенное поведение, не так ли? Ха-ха.   -  person Marco Bonelli    schedule 03.09.2019
comment
gcc отклоняет sizeof(double[SIZE_MAX]);   -  person M.M    schedule 03.09.2019


Ответы (1)


В стандарте C явно не указано, что типа size_t достаточно для работы с размерами всех объектов или типов, особенно для гипотетических типов, экземпляры которых на самом деле не созданы.

В C 2018 7.19 2 стандарт говорит, что size_t «является беззнаковым целым типом результата оператора sizeof». Это говорит нам о типе size_t, но не о значениях, которые могут возникнуть во время вычислений. В 5.2.4 стандарт признает, что реализации C обязательно имеют ограничения и что они должны ломаться в различных точках.

7.19 4 гласит: «Типы, используемые для size_t и ptrdiff_t, не должны иметь целочисленный ранг преобразования выше, чем у signed long int, если только реализация не поддерживает объекты, достаточно большие, чтобы сделать это необходимым». Это подтверждает наше желание, чтобы size_t мог представлять размеры всех поддерживаемых объектов, особенно потому, что это подразумевает, что существование объекта делает «необходимым» то, что size_t может представлять его, но это не явное утверждение, что size_t должен сделать это, и это не относится к гипотетическим типам, которые могут быть описаны, но не могут быть реализованы как объекты.

Если бы мы вычислили n * sizeof(double), мы узнали бы результат: 6.2.5 9 говорит: «Вычисление, включающее операнды без знака, никогда не может переполниться, потому что результат, который не может быть представлен результирующим целочисленным типом без знака, уменьшается по модулю числа, которое на единицу больше, чем наибольшее значение, которое может быть представлено результирующим типом». Однако с sizeof(double[n]) не совсем ясно, что это применимо, потому что, хотя n не имеет знака, это не прямой операнд sizeof, где происходит вычисление результата, который не может быть представлен. Стандарт явно не говорит нам, что результат этого sizeof будет уменьшаться таким же образом.

Таким образом, эта операция не покрывается стандартом C.

person Eric Postpischil    schedule 03.09.2019
comment
Согласно этой ссылке: size_t может хранить максимальный размер теоретически возможного объекта любого типа (включая массив). - person Ayxan Haqverdili; 03.09.2019
comment
@Ayxan: эта ссылка неверна. Я процитировал стандарт C в своем ответе, и он является авторитетным. - person Eric Postpischil; 03.09.2019
comment
Было бы уместно использовать в своем заключении хорошо известную фразу «неопределенное поведение»? - person ryyker; 03.09.2019
comment
@ryyker: я бы не решился его использовать. Как определено стандартом C, «неопределенное поведение» является абсолютным; это означает, что стандарт C вообще не налагает никаких требований на поведение. Это действительно может иметь место для sizeof(double[SIZE_MAX/sizeof(double) + 1]), но я думаю, что лучше рассматривать это как нечто, что комитет C не учел, а не что-то, что, по решению комитета, должно быть неопределенным. (Кроме того, я не уверен, что эта фраза хорошо понята. Многие люди, кажется, рассматривают ее как поведение, которое вы должны избегать, но это несовместимо со многими законными расширениями C.) - person Eric Postpischil; 03.09.2019
comment
Неопределенное поведение иначе обозначается в настоящем стандарте словами «неопределенное поведение» или отсутствием какого-либо явного определения поведения. (С18 4 п2). В противном случае, я думаю, что это закрывает проблему. - person ov2k; 03.09.2019