Что такое uintptr_t
и для чего его можно использовать?
Что такое тип данных uintptr_t
Ответ 1
uintptr_t
- это целочисленный тип без знака, который может хранить указатель данных. Что обычно означает, что он имеет тот же размер, что и указатель.
Опционально определяется в С++ 11 и более поздних стандартах.
Распространенная причина, по которой нужен целочисленный тип, который может содержать тип указателя архитектуры, состоит в том, чтобы выполнять целочисленные операции над указателем или скрывать тип указателя, предоставляя его как целочисленный "дескриптор".
Изменение: Обратите внимание, что у Стива Джессопа есть несколько очень интересных дополнительных деталей (которые я не буду красть) в другом ответе здесь для вас, педантичных типов :)
Ответ 2
Во-первых, в то время, когда задавался вопрос, uintptr_t
не было на С++. Это в C99, в <stdint.h>
, в качестве необязательного типа. Многие компиляторы С++ 03 предоставляют этот файл. Он также находится в С++ 11, в <cstdint>
, где снова он является необязательным, и который относится к C99 для определения.
В C99 он определяется как "непознанный целочисленный тип с тем свойством, что любой действительный указатель на void может быть преобразован в этот тип, а затем преобразован обратно в указатель на void, а результат будет сравниваться с исходным указателем".
Возьмите это, чтобы понимать, что он говорит. Он ничего не говорит о размере.
uintptr_t
может быть того же размера, что и void*
. Это может быть больше. Вероятно, это может быть меньше, хотя такая реализация на С++ приближается к извращению. Например, на некоторой гипотетической платформе, где void*
- 32 бита, но используется только 24 бита виртуального адресного пространства, вы можете иметь 24-разрядный uintptr_t
, который удовлетворяет этому требованию. Я не знаю, почему реализация будет делать это, но стандарт позволяет это.
Ответ 3
Это целое число без знака, которое точно соответствует размеру указателя. Всякий раз, когда вам нужно делать что-то необычное с помощью указателя - например, инвертировать все биты (не спрашивайте, почему), вы бросаете его на uintptr_t
и манипулируете им как обычное целое число, а затем отбрасываете назад.
Ответ 4
Уже есть много хороших ответов на часть "Что такое тип данных uintptr_t". Я попытаюсь решить, для чего он может быть использован? в этой статье.
В первую очередь для побитовых операций с указателями. Помните, что в С++ нельзя выполнять побитовые операции с указателями. По причинам см. Почему вы не можете выполнять побитовые операции с указателем на C, и есть ли способ обойти это?
Таким образом, для выполнения поразрядных операций над указателями нужно было бы наложить указатели на тип unitpr_t, а затем выполнить побитовые операции.
Вот пример функции, которую я только что написал, чтобы сделать побитовое исключение или 2 указателя для хранения в связанном списке XOR, чтобы мы могли проходить в обоих направлениях, как двойной список, но без штрафа за сохранение 2 указателей в каждом node.
template <typename T>
T* xor_ptrs(T* t1, T* t2)
{
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
}
Ответ 5
Риск получить еще один значок Necromancer, я хотел бы добавить одно очень хорошее использование для uintptr_t (или даже intptr_t), и это написание тестируемого встроенного кода. Я пишу в основном встроенный код, предназначенный для различных процессоров и в настоящее время процессоров. Они имеют различную внутреннюю ширину шины, а tenisilica - это фактически гарвардская архитектура с отдельным кодом и шинами данных, которые могут иметь разную ширину. Я использую стиль разработки, основанный на тестировании, для большей части моего кода, что означает, что я делаю модульные тесты для всех блоков кода, которые я пишу. Модульное тестирование на реальном целевом оборудовании - сложная задача, поэтому я обычно пишу все на ПК на базе Intel в Windows или Linux, используя Ceedling и GCC. Это, как говорится, много встроенного кода включает в себя битовое манипулирование и манипулирование адресами. Большинство моих машин Intel являются 64-битными. Так что, если вы собираетесь тестировать код манипулирования адресами, вам нужен обобщенный объект для математики. Таким образом, uintptr_t дает вам машинно-независимый способ отладки кода перед тем, как вы попытаетесь выполнить развертывание на целевом оборудовании. Другая проблема заключается в том, что для некоторых машин или даже моделей памяти в некоторых компиляторах указатели функций и указатели данных имеют разную ширину. На этих машинах компилятор может даже не разрешить приведение между двумя классами, но uintptr_t должен быть в состоянии удерживать любой из них.