Для перебора массива мы должны использовать size_t или ptrdiff_t?
В этом блоге запись Андрея Карпова под названием "О size_t
а также ptrdiff_t
" Он показывает пример,
for (ptrdiff_t i = 0; i < n; i++)
a[i] = 0;
Тем не менее, я не уверен, что это правильно, кажется, что должно быть
for (size_t i = 0; i < n; i++)
a[i] = 0;
Это правильно?
Я знаю, что мы также должны использовать что-то вроде memset
, но давайте избегать этого полностью. Я спрашиваю только о типе
3 ответа
В сообщении в блоге я утверждаю, что вы всегда должны воздерживаться от выделения блоков памяти больше, чем PTRDIFF_MAX
(*), потому что это приведет к тому, что компиляторы, такие как Clang и GCC, будут генерировать бессмысленный код, даже если вы не вычитаете указатели на этот блок таким образом, что это приводит к переполнению результата.
(*) Даже если malloc
успешно, когда вы передаете ему значение больше PTRDIFF_MAX
, Суть проблемы в том, что GCC и Clang генерируют только код, который ведет себя правильно, когда связан с таким malloc
, но Глибц обеспечивает malloc
функция, которая не реализует это ограничение.
Если вы соблюдаете это ограничение (которое я рекомендую вам: это сообщение в блоге), тогда оба типа одинаково верны.
Это сказало, так как только положительные смещения должны быть представлены, size_t
будет естественным выбором в вашем примере.
Использование ptrdiff_t
в порядке, так как a[i]
переводится как *(a + i)
,
Если вы возьмете два указателя, p1
а также p2
Рекомендуется использовать:
ptrdiff_t d = p2 - p1; // Assuming p2 - p1 is valid.
При условии, p2 == p1 + d
т.е. <ptr type> + ptrdiff_t
является допустимым выражением. Будь то ptrdiff_t
или же size_t
лучше, так как тип индекса зависит от мнения и / или стиля кодирования, используемого в команде.
Ответ на вопрос OP - да, size_t наиболее подходит для примера кода, где никакие значения указателя не вычитаются друг из друга, и нет проблем совместимости кросс-компилятора / библиотеки вокруг malloc
поведения. Независимо от разницы в диспетчерах кучи, в C массив может быть SIZE_MAX
байтов в длину, и это требует size_t
представлять это. Ничто в стандарте не требует, чтобы менеджер кучи мог выделять все пространство памяти процесса в куче или выделять до SIZE_MAX
байтов в этом отношении, но массив может быть SIZE_MAX
в длину, следовательно size_t
является целесообразным.
Даже если n
подписан, используя ptrdiff_t
за i
не поможет, как начальный i < n
тест все равно не пройдёт, если n
отрицательно, потому что i
инициализируется до нуля. Там нет индекса в i
это size_t
Индекс не может получить доступ. Единственное место, которое ptrdiff_t
необходим, где вы вычитаете одно значение указателя из другого, и ОП не спрашивает об этом.