In comments user R.. points out that the following is likely incorrect if the addresses the code is dealing with are not valid within the current process. I've asked the OP for clarification.
Do not use uintptr_t
for pointer arithmetic if you care about the portability of your code. uintptr_t
is an integer type. Any arithmetic operations on it are integer arithmetic, not pointer arithmetic.
If you have a void*
value and you want to add a byte offset to it, casting to char*
is the correct approach.
It's likely that arithmetic on uintptr_t
values will work the same way as char*
arithmetic, but it absolutely is not guaranteed. The only guarantee that the C standard provides is that you can convert a void*
value to uintptr_t
and back again, and the result will compare equal to the original pointer value.
And the standard doesn't guarantee that uintptr_t
exists. If there is no integer type wide enough to hold a converted pointer value without loss of information, the implementation just won't define uintptr_t
.
I've actually worked on systems (Cray vector machines) where arithmetic on uintptr_t
wouldn't necessarily work. The hardware had 64-bit words, with a machine address containing the address of a word. The Unix-like OS needed to support 8-bit bytes, so byte pointers (void*
, char*
) contained a word address with a 3-bit offset stored in the otherwise unused high-order 3 bits of the 64-bit word. Pointer/integer conversions simply copied the representation. The result was that adding 1 to a char*
pointer would cause it to point to the next byte (with the offset handled in software), but converting to uintptr_t
and adding 1 would cause it to point to the next word.
Bottom line: If you need pointer arithmetic, use pointer arithmetic. That's what it's for.
(Incidentally, gcc has an extension that permits pointer arithmetic on void*
. Don't use it in portable code. It also causes some odd side effects, like sizeof (void) == 1
.)
uintptr_t
variable followed by a cast tochar*
will get you the same result as will applying the math directly to thechar*
theuintptr_t
was derived from, although I think it'd be crazy if this didn't hold. – Markswoman