uintptr_t
- это тип integer , который позволяет безопасно хранить значение указателя в целом числе. Поскольку разные машины и архитектуры имеют разные размеры указателей, этот тип позволяет преобразовывать указатель в целочисленный тип, не беспокоясь о выборе правильного размера целого числа (например, 32-битных или 64-битных целых) в зависимости от машины. Это облегчает написание переносимого кода.
uintptr_t
- это , а не тип указателя. Это означает, что вы не можете разыменовать его так же, как вы не можете разыменовать int
. Чтобы использовать его в качестве указателя, вы должны привести его обратно к указателю.
char* char_ptr = (char*)bufferptr;
*char_ptr = *c;
Если вы хотите выполнять манипуляции с указателем (включая арифметику указателя c), я бы порекомендовал сохранить ваши указатели. в виде указателей, а не , преобразующих их в uintptr_t
.
Поскольку размер char
гарантированно равен 1, все вычисления, которые вы выполняете на char*
, точно такие же, как вычисления, которые вы выполняете для целого числа, например
char c = 'A'
char* p0 = &c;
uintptr_t p_casted = (uintptr_t)p0;
char* p1 = p0 + 42;
char* p2 = (char*)(p_casted + 42);
В этом примере p1
и p2
будут иметь точно такое же значение. p0 + 42
добавит в 42 раза размер char
к адресу, содержащемуся в p0
, но, поскольку размер char
всегда равен 1, это точно так же, как и во второй версии.
Результат будет другим для типа, размер которого не равен 1 (например, если p0
было int*
или float*
). Однако, если вы хотите выполнять простые целочисленные вычисления (скажем, добавлять или вычитать смещение) к значению указателя, я все равно рекомендовал бы приведение к char*
вместо intptr_t
, если вам действительно не нужно выполнять специальные целочисленные операции над значением указателя (например, инвертировать некоторые биты или что-то вроде этого), как подсказывают ответы на этот вопрос .