Учитывая требование, чтобы мне нужно было сохранить значение "общего" указателя в структуре и не интересоваться самой заостренной памятью, я считаю более семантически правильным хранить его как intptr_t
, чем void*
. Вопрос в том, подходит ли a uintptr_t
или нет, а когда один предпочтительнее другого в целом?
Когда uintptr_t предпочитается над intptr_t?
Ответ 1
Это в основном стилистический аргумент (оптимизирующий компилятор, вероятно, сгенерировал бы тот же или очень похожий код). Однако сравнение указателей может быть непростой задачей.
Помните, что в сравнении с чисто стандартным C-указателем сравнение имеет смысл только для указателей на одни и те же совокупные данные. Вероятно, вам не разрешено сравнивать два результата с malloc
, например. для сохранения отсортированного массива указателей.
Я бы сохранил их как void*
, а также как uintptr_t
. Подписанный intptr_t
имеет неудобство для разделения отрицательных и положительных чисел, и где они исходят из значительных указателей на приложения, это, вероятно, не приветствуется.
Обратите внимание, что a void*
не может быть разыменован: как uintptr_t
, вы должны указать его, чтобы сделать что-то полезное с данными, указанными по адресу; однако указатели void*
могут быть переданы таким подпрограммам, как memset
PS. Я предполагаю обычный процессор (например, некоторые x86, PowerPC, ARM,...) с плоским виртуальным адресным пространством. Вы могли бы найти экзотические процессоры - возможно, некоторые DSP - с очень значительными различиями (и, возможно, на которых intptr_t
не всегда имеет значение, помните, что в 1990-е годы Cray Y- MP суперкомпьютеров sizeof(long*) != sizeof(char*)
; в то время C99 не существовало, и я не уверен, что его <stdint.h>
может быть значимые на таких машинах)
Ответ 2
Это звучит очень странно, так как это потребует отбросов. A void *
в C имеет огромное преимущество в том, что он преобразует в/из других типов указателей объектов без приведения, что является чистым способом.
Это говорит о том, что uintptr_t
может иметь смысл, если вы хотите сделать что-то с битами указателя, который вы не можете сделать так разумно с помощью целого числа со знаком (например, смещение их вправо, например).
Ответ 3
Если вы хотите манипулировать значением арифметически (например, для его шифрования), у вас гораздо больше гибкости с неподписанным типом (где арифметические обходы), чем с подписанным типом (где арифметическое переполнение дает поведение undefined).