The following works:
void* p = reinterpret_cast<void*>(0x1000);
But looks 'incorrect/unsafe' eg. 0x1000 is an int
and not even uintptr_t
, I could fix this, but is there a better/safer method of casting ?
The following works:
void* p = reinterpret_cast<void*>(0x1000);
But looks 'incorrect/unsafe' eg. 0x1000 is an int
and not even uintptr_t
, I could fix this, but is there a better/safer method of casting ?
0x1000 is an
int
and not evenuintptr_t
, I could fix this, but is there a better/safer method of casting
0x1000
is int
, and in reinterpret_cast<void*>(0x1000)
the compiler emits a sign extension instruction (sign is 0 here) or a plain register load instruction with an immediate operand to make the value as wide as void*
.
For many reasons the compiler cannot possibly know whether 0x1000
represents a valid address, so it has to comply and assume that it is a valid address.
Casting integers representing addresses to pointers with reinterpret_cast
is currently the existing practice.
You can create a pointer from an integer with reinterpret_cast
.
However a pointer that does not point to to an existing object (or 1 past the last element in an array with an object being considered the sole element in an imaginary array for this purpose, or is the null pointer) has an invalid pointer value. Dereferencing is UB and other operations with invalid pointer values are implementation specific so you need to make sure your compiler allows the operations you do with these pointers.
void* p = reinterpret_cast<void*>(0x1000); // invalid pointer,
// operations on it are implementation defined
§6.7.2 Compound types [basic.compound]
[...] Every value of pointer type is one of the following:
3.1 — a pointer to an object or function (the pointer is said to point to the object or function), or
3.2 — a pointer past the end of an object (8.5.6), or
3.3 — the null pointer value (7.11) for that type, or
3.4 — an invalid pointer value
§8.5.1.10 Reinterpret cast [expr.reinterpret.cast]
- A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined. [...]
- A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.
You are allowed to convert from integer to pointer, but if the resulting pointer value doesn't point to an existing object (or one past an object) the resulting pointer has an invalid value.
Now regarding what you can do with invalid pointers:
§6.6.4 Storage duration [basic.stc]
- [...] Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior 35
35) Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault.
This post was heavily edited because it was wrong in its first iterations. Warm thanks to the community for correcting and challenging me.
The following ... looks 'incorrect/unsafe' ... is there a better/safer method of casting ?
As another answer pointed out, this is "incorrect" to the extent of having implementation-defined behavior. Also, you're using a magic number.
But the issue is not the casting, I believe. I really kind of doubt you need to initialize a void*
variable with literal address. Why?
If there's some kind of typed value at that address, then don't use void *
, but rather a typed pointer. Even if you later want to pass that pointer to memset()
or memcpy()
or even some callback function which takes void *
- delay the type erasure.
Where do you get that number from? Surely you know magic numbers are bad, right? Well, at the very least use something like
constexpr const uintptr_t sound_card_memory_mapped_buffer_address { 0x1000 };
this takes care of one of your concerns (not uintptr_t
), and is also clearer to read, even if you stay with a void *
:
void* p = reinterpret_cast<void*>(sound_card_memory_mapped_buffer_address);
p
is a poor choice of name for a variable. Rename it according to its use.
Do you really need to initialize p
at all? :
If you're not using it at the moment, why even initialize it? Try just not declaring it until it's about to be used (if at all).
If you're about to use it, why even declare it? Try:
do_something_with(sound_card_memory_mapped_buffer_address);
and no p
in sight.
Obviously I have more questions than answers for you, since you only provided us a one-liner.