Для перебора массива мы должны использовать 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 необходим, где вы вычитаете одно значение указателя из другого, и ОП не спрашивает об этом.

Другие вопросы по тегам