3 ms·
The conversion is well defined, so the creating a pointer with `(int *) 0` is fully legal, but the dereference itself is UB. https://en.cppreference.com/w/cpp/
by compiler-guy 2y ago
The conversion is well defined, so the creating a pointer with `(int *) 0` is fully legal, but the dereference itself is UB.
https://en.cppreference.com/w/cpp/language/nullptr https://en.cppreference.com/w/cpp/language/nullptr
https://en.cppreference.com/w/cpp/language/pointer https://en.cppreference.com/w/cpp/language/pointer Nullptr section is not directly linkable, but:
"A pointer whose value is null does not point to an object or a function (the behavior of dereferencing a null pointer is undefined), and compares equal to all pointers of the same type whose value is also null."
- shadowgovt 2y agoThis is where I get a bit lost in the spec, I think... Can the compiler know that the value of `i` is 0? If yes, then the spec says regardless of how the implementation defines nullptr, assigning literal 0 to a pointer variable is assigning a nullptr (i.e. the compiler must turn `0` into whatever the nullptr is in the underlying implementation). If no, then 0 is just some unknown value and the assignment gives you an implementation-dependent (not necessarily invalid) pointer to whatever address `0` means on this architecture.
- int_19h 2y agoThe C spec only requires that integer constant expressions that have zero value are nullptrs. The moment you assign it to an int variable, it's no longer a constant expression as far as the language is concerned, so if you then cast that int variable to a pointer, the result is indeterminate. (Note also that in C, unlike C++, "const" really means that it is read-only, not that it is a constant expression, so that doesn't change anything.) However, even if the resulting pointer is not a null pointer, dereferencing it is still UB unless it points at a valid C object. So if the compiler can statically prove that for this architecture, there's no valid C object at that address (e.g. because the compiler itself never produces code that would result in objects placed at that address), it can still treat it as UB, same as dereferencing a literal 0.
- shadowgovt 2y agoHow does that interact with using C++ to access hardware features via direct memory, such as UART registers on embedded systems? Is all of that considered UB because the compiler can't prove there's anything at the UART "magic" addresses?
- int_19h 2y agoAs far as ISO C++ is concerned, it is. In practice, of course, a useful C++ compiler would let you do it, somehow. But that is firmly in the realm of implementation-specific stuff (keeping in mind that UB can mean anything including being well-defined by a specific implementation.
- EasyMark 2y ago[deleted]wrong thread
- shultays 2y agothe dereference itself is UB My point was the dereference itself could be a valid dereference depending on architecture. You can have a pointer to address 0 or 42 or whatever and it all depends on what is mapped to that address. Could be ram, could be some other hardware etc I guess I was nitpicking. For gcc and the target architecture that is compiling that code it is UB so it is optimizing things with that information Does "A pointer whose value null" always means that it is literally value 0? That is how it is in practice but how C++ handles architectures where 0 is a valid address that a program can dereference? Does cpp compilers use another value for nullptr in such architectures?
- int_19h 2y agoIt is UB for any C compiler and for any architecture because the language defines it as such. However, because it is UB, the compiler doesn't need to do anything special if there's no trap on null dereference, since "reading something" is a perfectly valid subset of UB. The only thing that it needs to ensure is that no global, local, or heap-allocated C object can end up at address 0, which is easily done by "wasting" a single word at that address (or using it for some internal purposes). It may still be that there is something useful at address 0 that some code may want to access. For example, in real-mode x86, the interrupt vector table starts at that address, so if you want to change what gets called to handle INT 0h, you'd need to write into it. But at this point you're already deep into architecture-specific stuff, and so it's not unreasonable to expect you to use some special facilities that a compiler for this architecture might provide to enable it, instead of the usual pointer dereference.
- shultays 2y agoI am a bit confused, in another post you mentioned The C spec only requires that integer constant expressions that have zero value are nullptrs. The moment you assign it to an int variable, it's no longer a constant expression as far as the language is concerned, so if you then cast that int variable to a pointer, the result is indeterminate It is not an integer constant that gets assigned to a pointer so this is not a null pointer in that case? It is just a pointer with address of 0 (which very well might be the implementation of nullptr but from my understanding that is not required?) so shouldn't nullptr dereferencing rule not apply here?