As has been stated in the comments: Accessing the same piece of memory as two different types is UB. So, that's the formal answer (note that "UB" does include "doing precisely what you would expect if you are a sane person reading the code" as well as "just about anything other than what a sane person reading the code would expect")
Having said that, it appears that all popular compilers tend to cope with this fairly well. It is not unusual to see these sort of constructs (in "good" production code - even if the code isn't strictly language-lawyer correct). However, you are at the mercy of the compiler "doing the right thing", and it's definitely a case where you may find compiler bugs if you stress things too harshly.
There are several reasons that the standard defines this as UB - the main one being that "different types of data may be stored in different memory" and "it can be hard for the compiler to figure out what is safe when someone is mucking about casting pointers to the same data with different types" - e.g. if we have a pointer to a 32-bit integer and another pointer to char, both pointing to the same address, when is it safe to read the integer value after the char value has been written. By defining it as UB, it's entirely up to the compiler vendor to decide how precisely they want to treat these conditions. If it was "defined" that this will work, compilers may not be viable for certain processor types (or code would become horribly slow due to the effect of the liberal sprinkling of "make sure partial memory writes have completed before I read" operations, even when those are generally not needed).
So, in summary: It will most likely work on most processors, but don't expect any language lawyer to approve of your code.