Convert Pointer &p to Integer and Back

What is a valid conversion from pointer (&p) to integer and back?

Do I just do a cast? or just the same as Int to Pointer and use the & when needed?


Last edited on
A reinterpret_cast

2) A pointer can be converted to any integral type large enough to hold all values of its type (e.g. to std::uintptr_t)
3) A value of any integral or enumeration type can be converted to a pointer type. A pointer converted to an integer of sufficient size and back to the same pointer type is guaranteed to have its original value, otherwise the resulting pointer cannot be dereferenced safely (the round-trip conversion in the opposite direction is not guaranteed; the same pointer may have multiple integer representations) The null pointer constant NULL or integer zero is not guaranteed to yield the null pointer value of the target type
...
8) On some implementations (in particular, on any POSIX compatible system as required by dlsym), a function pointer can be converted to void* or any other object pointer, or vice versa. If the implementation supports conversion in both directions, conversion to the original type yields the original value, otherwise the resulting pointer cannot be dereferenced or called safely.
https://en.cppreference.com/w/cpp/language/reinterpret_cast
Let T be some arbitrary type:
1
2
3
4
5
T *p = /*...*/;
T2 i = (T2)p;
T *q = (T *)i;
static_assert(std::is_integral<T2>::value);
assert(p == q);
T2 can only be either uintptr_t or intptr_t. Any other integer type is not guaranteed to be able to store pointers without losing information.
Needless to say, you should be very careful when casting the integer back into a pointer. Casting to a pointer type different from the original pointer type and then dereferencing the new pointer causes undefined behavior.
^^ true but for the present, I can't think of any major system that has a pointer that won't fit in an unsigned 64 bit int.

This isnt something one normally does other than for debugging or study.
Last edited on
Pointers to member functions may be (typically are) larger.

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <cstdint>

int main()
{
    const auto ptr_mem_fun = &std::ostream::clear ;

    std::cout << sizeof(ptr_mem_fun) << '\n'
              << sizeof(std::uintmax_t) << '\n' ;
}

https://coliru.stacked-crooked.com/a/42e48a29ddf045eb
Thanks for the input guys. I forgot to include that I'm only using C for this problem.
Just do cast then.

It's commonly used in Windows programming, passing data in a Windows Message with Send/PostMessage.
LRESULT SendMessage(
[in] HWND hWnd,
[in] UINT Msg,
[in] WPARAM wParam,
[in] LPARAM lParam
);
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage

Those wParam/lParam are short/long ints that almost always have to cast if you're not sending ints. For example, strings will be cast to long for lParam, and back to a char* in the handler.
WPARM/LPARAM are 32/64 bit depending upon whether compiling for 32/64 bit so will always be large enough to contain a pointer address.

Also note that LPARAM is a signed type and WPARAM is an unsigned type.

https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types

should be portable in C so not considering Windows only.
C99:
If the implementation provides intptr_t and/or uintptr_t, then a cast from a pointer to an object type (including cv void) to these types is always well-defined.
https://en.cppreference.com/w/c/language/cast#Notes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdint.h>

inline uintptr_t to_integer( const volatile void* ptr ) { return (uintptr_t)ptr ; }

#define to_pointer( int_value, type ) ( (type*)int_value )

int main()
{
    double dbl = 1234.56 ;
    uintptr_t int_val = to_integer( &dbl ) ; // pointer to integer

    const double* const pd = to_pointer( int_val, const double ) ; // integer to pointer
    if( pd == &dbl ) puts("ok") ;
}
Topic archived. No new replies allowed.