Когда uintptr_t предпочитается над intptr_t?

Учитывая требование, чтобы мне нужно было сохранить значение "общего" указателя в структуре и не интересоваться самой заостренной памятью, я считаю более семантически правильным хранить его как intptr_t, чем void*. Вопрос в том, подходит ли a uintptr_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).