Post by Thiago MacieiraPost by Andrey SemashevIs there actually a concept of a pointer to a register in any of the
hardware architectures? I mean, a pointer as a runtime value that can be
stored in memory or another register.
Not in the sense that you're thinking. Modern architectural registers are not
addressable in memory, only by instructions. The closest are indirect
registers, such as several types of OS-level registers found in IA-64.
What Melissa was talking about maps more directly to modern MMIO. In some
older architectures (Apollo Guidance Calculator comes to mind), registers were
actually addressable in a special portion of memory.
Post by Andrey SemashevRegarding your original examples, I don't see why there would be any
reason to generate a "read" instruction for these functions, unless the
hardware has to load the 0x12345678 constant from memory. Otherwise, I
would expect both functions to be equivalent and do nothing but to load
the constant to a register (and then maybe store it to the stack to
return or assign it to a variable). That is assuming the code is not
removed by DCE or transformed to something different entirely depending
on the context. None of the functions read from address 0x12345678.
I didn't understand what Melissa's problem was either. But it's not trying to
load the 0x12345678 constant, but read a value from the address 0x12345678.
Since the memory location is accessed volatilely, it can't be deleted by the
compiler, provided the code was actually reached (note:: volatile != atomic).
DCE obviously still applies, as do the optimisations based on UB.
Post by Andrey SemashevI agree that dereferencing a null pointer is useful and doesn't cause
any effect that could have an UB in real life. But the never-null
property of references is also useful. If I had to choose between the
two, I'd probably choose the former.
Sorry, I disagree. Dereferencing a pointer is akin to loading a value from it,
so dereferencing a null pointer is like trying to load a value from the zero
address. On most systems, that will cause a general protection fault -- but
not all of them. Hence, UB.
Dereferencing a pointer ("indirection" is the standard's term) is a
conversion from a pointer to an lvalue. The load (lvalue-to-rvalue
conversion), if any, is separate and comes later. There are at least three
other things that could happen to the result of indirection through a
pointer: it could be bound to a reference (which would then require that
the pointer points to suitable storage for the underlying type of the
reference), its address could be taken (in which case, per the direction of
core issue 232, there is no problem and you get back your original
pointer), or it could be discarded (in which case a load may be synthesized
if the type of the lvalue is volatile-qualified).
If you keep in mind that indirection, reference binding, and the
lvalue-to-rvalue conversion are three separate operations, the behavior
here is a lot less confusing. (And yes, it'd be nice if we didn't have so
much complexity in the first place, but I think that ship has sailed.) So:
int *p = nullptr;
*p; // ok (per core issue 232), indirection has no side-conditions
&*p; // ok (per core issue 232), address of this empty lvalue is a null
pointer value
int &r = *p; // UB: reference not bound to suitable storage for int object
int n = *p; // UB: lvalue *p does not denote an 'int' object within its
lifetime
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.