2016-11-29 10 views
0

Предположим, я хочу отслеживать, сколько ассигнований моей программы сделано, поэтому я увеличиваю/уменьшаю счетчик, когда я malloc или free. Аналогично, я могу подсчитать длину связанного списка.Какой тип C следует использовать для подсчета объектов в памяти?

Какой тип следует использовать для такого значения? Я думаю, что худшим случаем для «количества объектов в памяти» является количество байтов в адресном пространстве. То есть мой счетчик должен быть того же размера, что и тип указателя. Это наводит на мысль, я должен установить свой счетчик, как:

void * num_allocated_objects = 0; 

Однако, это выглядит как нетрадиционное использование void*! Один источник говорит мне, что я должен использовать size_t: "You use size_t when you are counting something, and are sure that it cannot be negative."

Я не уверен. size_t is "used to represent the size of an object". Эти два ответа кажутся несовместимыми: я могу представить себе систему, в которой возможное количество объектов больше размера самого большого объекта в байтах. Использование size_t для подсчета вещей в памяти должно предполагать, что самым большим объектом в памяти является размер всего адресного пространства.

Каков правильный, идиоматический тип C для подсчета объектов в памяти? Это size_t, или тип указателя, или что-то еще?

+0

1) Указатели - это ** нет ** целые числа, а не для подсчета. 2) Вы не можете делать арифметику на 'void *'. 3) Как бы вы проверили указатель? Сравнение указателей с несвязанными адресами вызывает UB. Сказал, что: это зависит от реализации. – Olaf

ответ

1

Если вы хотите быть педантичным, тогда вы должны использовать uintptr_t, который является (беззнаковым) целым числом, гарантированным достаточно большим, чтобы удерживать значение указателя.

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

+0

Ага, я не знал о 'uintptr_t' - это звучит прямо для меня! Кстати, почему вы называете это педантичным? Что бы вы использовали для этой цели? – jameshfisher

+0

Nitpick: 'uintptr_t' гарантируется только преобразование в/из' void * 'без изменения значения между ними. Теоретически могут существовать архитектуры, предоставляющие разные пространства имен для разных типов, поэтому фактическое пространство памяти может быть больше, чем 'void *' и, следовательно, 'uintptr_t' может удерживаться. – Olaf

+0

Ну, может быть, нечестно сказать, что это педантично. Похоже, что если вы загружаете свой собственный распределитель памяти и имеете много этих значений, плавающих вокруг, меньший тип с установленными ограничениями (например, 'size_t') может быть лучше. Но для одного счетчика я не вижу проблемы с выбором 'uintptr_t'. Одно из соображений заключается в том, сколько распределений потребуется для переполнения вашего счетчика, и практично ли в рамках вашего приложения считать, что переполнение может действительно произойти. – paddy