Что такое тип данных 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 должен быть в состоянии удерживать любой из них.