Что такое тип данных uintptr_t

Что такое uintptr_t и для чего его можно использовать?

4 ответа

Решение

uintptr_t целочисленный тип без знака, способный хранить указатель Что обычно означает, что это тот же размер, что и указатель.

Опционально определяется в C++11 и более поздних стандартах.

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

Изменить: Обратите внимание, что у Стива Джессопа есть некоторые очень интересные дополнительные детали (которые я не буду красть) в другом ответе здесь для вас педантичных типов:)

Во-первых, в то время, когда был задан вопрос, uintptr_t не было в C++. Это в C99, в <stdint.h>, как необязательный тип. Многие компиляторы C++03 предоставляют этот файл. Это также в C++11, в <cstdint>где, опять же, это необязательно, и который относится к С99 для определения.

В C99 это определяется как "целочисленный тип без знака со свойством, что любой действительный указатель на void может быть преобразован в этот тип, затем преобразован обратно в указатель на void, и результат будет сравниваться равным исходному указателю".

Примите это, чтобы означать, что это говорит. Это ничего не говорит о размере.

uintptr_t может быть такого же размера, как void*, Это может быть больше. Вероятно, он может быть меньше, хотя такая реализация на C++ подходит извращенно. Например, на некоторой гипотетической платформе, где void* 32 бита, но используется только 24 бита виртуального адресного пространства, вы можете иметь 24-битный uintptr_t который удовлетворяет требованию. Я не знаю, почему реализация сделала бы это, но стандарт разрешает это.

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

Уже есть много хороших ответов на часть "что такое тип данных uintptr_t". Я попытаюсь ответить на вопрос "для чего он может быть использован?" часть в этом посте.

В первую очередь для побитовых операций с указателями. Помните, что в C++ нельзя выполнять побитовые операции с указателями. По причинам см. Почему вы не можете выполнять побитовые операции с указателем в C, и есть ли способ обойти это?

Таким образом, чтобы выполнять побитовые операции с указателями, необходимо привести указатели к типу unitpr_t, а затем выполнить побитовые операции.

Вот пример функции, которую я только что написал для выполнения побитового исключения или двух указателей для сохранения в связанном списке XOR, чтобы мы могли перемещаться в обоих направлениях, как дважды связанный список, но без штрафа за сохранение двух указателей в каждом узле,

 template <typename T>
 T* xor_ptrs(T* t1, T* t2)
 {
     return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
  }

Рискуя получить еще один значок Некроманта, я хотел бы добавить одно очень хорошее применение для uintptr_t (или даже intptr_t), а именно написание тестируемого встроенного кода. Я пишу в основном встраиваемый код, предназначенный для различных процессоров, а в настоящее время - процессоров tensilica. Они имеют различную ширину собственной шины, а тензилика на самом деле представляет собой архитектуру Гарварда с отдельным кодом и шинами данных, которые могут иметь разную ширину. Я использую стиль разработки, основанный на тестах, для большей части своего кода, что означает, что я провожу модульные тесты для всех единиц кода, которые пишу. Модульное тестирование на реальном целевом оборудовании - проблема, поэтому я обычно пишу все на ПК на базе Intel либо в Windows, либо в Linux, используя Ceedling и GCC. При этом большая часть встроенного кода включает в себя перестановку битов и манипуляции с адресами. Большинство моих машин Intel 64-битные.Итак, если вы собираетесь протестировать код манипулирования адресами, вам понадобится обобщенный объект для математических вычислений. Таким образом, uintptr_t дает вам машинно-независимый способ отладки кода перед попыткой развертывания на целевом оборудовании. Другая проблема заключается в том, что для некоторых машин или даже моделей памяти на некоторых компиляторах указатели функций и указатели данных имеют разную ширину. На этих машинах компилятор может даже не разрешать преобразование между двумя классами, но uintptr_t должен иметь возможность удерживать и то, и другое. - Изменить - было указано @chux, это не является частью стандарта, и функции не являются объектами в C.Однако обычно это работает, и, поскольку многие люди даже не знают об этих типах, я обычно оставляю комментарий, объясняющий обман. Другие поиски в SO по uintptr_t предоставят дальнейшие объяснения.Также в модульном тестировании мы делаем то, что никогда бы не сделали в продакшене, потому что ломать вещи - это хорошо.

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