1

Is there any difference between (uintptr_t) and (uint8_t *)? Which is more portable?

Based on usage, can they be used interchangeably?

Aison
  • 33
  • 3

2 Answers2

2

uintptr_t is an unsigned integer large enough to contain a void *, to which any pointer but a function pointer can be converted.

uint8_t * is a pointer to a uint8_t.

You ask if there are any differences, but I'm having problems coming up with any meaningful similarities. There just about as different as night and calendar.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Can you replace uintptr_t with (uint8_t *) without any consequences? – Aison Apr 06 '22 at 16:39
  • 1
    @Aison No you cannot – Willis Hershey Apr 06 '22 at 16:41
  • @Aison The answer is clearly stating that these types are not interchangeable. Like "night and calendar"." – Eugene Sh. Apr 06 '22 at 16:42
  • Any reasons? It seems to me that you can perform arithmetic operations on them and both have the same outputs. – Aison Apr 06 '22 at 16:43
  • 1
    @Aison `uint8_t *a = ..., *b = ...;` now try `a + b;` - the same with two `uintptr_t`'s will of course work fine, since it's just a normal unsigned integer. – Ted Lyngmo Apr 06 '22 at 16:44
  • Ah I see. Besides arithmetic operations, any cases that we use uintptr_t instead of (void *) – Aison Apr 06 '22 at 16:49
  • 1
    "uintptr_t is an unsigned integer large enough to contain a pointer." -->more like "uintptr_t is an unsigned integer large enough to contain a `void *` pointer." which covers most pointers aside from function pointers. – chux - Reinstate Monica Apr 06 '22 at 17:01
  • @chux - Reinstate Monica, So that means `int *p; (uintptr_t)p` should be `int *p; (uintptr_t)(void *)p`? Updated. – ikegami Apr 06 '22 at 17:11
  • Re "*It seems to me that you can perform arithmetic operations on them*", Not really, no. It's meaningless to perform arithmetic on a `uintptr_t`, and there are very strict limits on what arithmetic operations can be taken on a pointer. For example, `uint8_t b = 3; uint8_t *p = &b; p = p + 1;` is valid, but `uint8_t b = 3; uint8_t *p = &b; p = p + 2;` isn't. – ikegami Apr 06 '22 at 17:14
  • @ikegami "Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined." (C17 6.3.2.3 Pointers). Going through `void*` to and from is well defined to form equivalent pointers. Without `void*`, the spec is fuzzier on the equivalent part. Rarely an issue to skip `void*` unless `void*, int *` have different encodings/sizes. Something uncommon in 2022. – chux - Reinstate Monica Apr 06 '22 at 17:56
0

I would say {signed,unsigned,} char* as neither uint8_t nor uintptr_t are guaranteed to be defined, strictly speaking.

char_type * is not interchangeable with uintptr_t, however. While you can use char_type * to point at the bytes of an object, you can do wilder pointer arithmetic with uintptr_t because then you don't necessarily get undefined behavior cases if you end up pointing at a wrong place.

E.g.:

#include <stdio.h>
#include <stdint.h>
int main(){
    char a[]={11,22,33};
    //for(char *p=a+2; p!=a-1;--p)
    //  printf("%d\n", *p); //undefined reverse iteration: can't point to &a[-1]
    for(uintptr_t p=(uintptr_t)(a+2); p!=(uintptr_t)a-1;--p) 
        printf("%d\n", *(char*)p); //OK; (uintptr_t)&a[0] - 1 is just a number
}
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142