Должен ли я всегда использовать size_t при индексации массивов?

Нужно ли мне всегда использовать size_t при индексации массива, даже если массив недостаточно велик, чтобы превышать размер int?

Это не вопрос о том, когда я должен использовать size_t. Я просто хочу знать, если, например, программа, имеющая 2 ГБ доступной памяти (все эти поля могут быть проиндексированы int32), но с этой памятью (виртуальная память), назначенная «полям» 14 ГБ - 16 ГБ компьютера ОЗУ.

Будет ли это всегда ошибкой при индексации памяти, если я использую int32 вместо size_t (или unsigned long int) в этом случае?

Возможно, вопрос больше о виртуальной памяти, чем об указателях.

Индексация массива не связана с оперативной памятью хост-машины. Причина, по которой size_t рекомендуется, заключается в том, что она делает вашу программу переносимой.

Mukul Gupta 10.04.2019 04:58

Обычно программа не должна заботиться о том, сколько памяти установлено на машине, на которой она работает. Но если логика программы диктует, что будет нижний предел количества элементов, вы можете использовать меньший тип индекса.

Galik 10.04.2019 05:00
size_t гарантированно сможет проиндексировать каждый байт всего, что вы ему подбрасываете. Удобно иногда.
user4581301 10.04.2019 05:00

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

n. 1.8e9-where's-my-share m. 10.04.2019 05:04

@ user4581301: Стандарт C не дает такой гарантии.

Eric Postpischil 10.04.2019 05:11

@EricPostpischil: да. В частности, он может содержать размер максимально возможного массива, поскольку массив — это тип объекта. Поэтому, если вы можете проиндексировать его, размер (в байтах) подходит для size_t. А так как элементы массива состоят как минимум из одного байта, то и каждый индекс может. Путаница может быть связана с тем, что size_t не гарантирует, что он будет содержать сумму размеров нескольких объектов.

MSalters 21.08.2019 00:20

@MSalters: это не так. Стандарт C определяет (C 2018 7.19 2), что size_t — это беззнаковый целочисленный тип результата оператора sizeof. Но это говорит нам только о типе, а не о значении. Стандарт не гарантирует, что размеры не будут переполнять тип, равно как и то, что арифметические операции не будут переполнять различные типы int.

Eric Postpischil 21.08.2019 00:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
17
7
2 692
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

Это не означает, что это требуется или даже обязательно рекомендуется для индексации. Вы можете использовать любой целочисленный тип, достаточно большой для индексации массива. int_fast32_t может быть быстрее, uint_least16_t может быть меньше по структуре и так далее. Знайте свои данные, и вы сможете сделать правильный выбор.

Следует учитывать, что на некоторых платформах для использования подписанного индекса может потребоваться дополнительная инструкция расширения знака. Например, вот x86:

// movzx eax, BYTE PTR [rcx+rdx]
// ret
char get_index(char *ptr, unsigned idx)
{
   return ptr[idx];
}

// ; sign extending idx from 32 bits to 64 bits with movsx here.
// movsx rdx, edx     
// movzx eax, BYTE PTR [rcx+rdx]
// ret
char get_index(char *ptr, int idx)
{
   return ptr[idx];
}

Виртуальная память выходит за рамки C или C++. С их точки зрения, вы просто индексируете память, и ваша платформа должна заставить это работать. На практике ваше приложение использует только виртуальные адреса; ваш ЦП/ОС переводит виртуальный адрес в физический за кулисами. Это не то, о чем вам нужно беспокоиться.

Чтобы избежать сбоев программы, программист всегда должен использовать тип индекса, по крайней мере такой же большой, как тип, возвращаемый методом size(). Это гарантирует, что индекс никогда не переполнит любой возможный размер массива. Реализация массива обычно гарантирует, что его размер во время выполнения никогда не переполнит тип, возвращаемый методом size(). Это означает, что тип индекса должен быть:

  • size_t в случае char[N], uint8_t[N], int[N] и т. д.
  • size_t в случае std::vector и std::list
  • int в случае QList и QVector
  • произвольное целое число точности (aint) в случае битовых массивов (если метод битового массива size() возвращает aint)
  • aint в случае сжатых в памяти массивов (если метод массива size() возвращает aint)
  • aint в случае массивов, охватывающих несколько машин (если метод size() массива возвращает aint)
  • Другие языки, кроме C++:
    • int в случае java.util.Collection и его подклассов

Подводя итог: безопасный тип индекса — это тип, возвращаемый методом size().

Примечание. Если метод size() возвращает беззнаковый size_t, то знаковые int и ssize_t не являются безопасными типами индексов. В случае gcc и clang флаги компилятора -Wsign-compare (включены -Wall) и -Wconversion можно использовать для предотвращения большинства этих случаев.

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