In C, we cannot use & to find out the address of a register variable but in C++ we can do the same. Why is it legal in C++ but not in C? Can someone please explain this
I assume that the keyword wouldn't have even made it into the language if it weren't for C compatibility. While I can not speak with any authority, if this is so, it seems to me there is a practical reason for it to be legal beyond simply a standard-enforced "the compiler is smarter than you" clause: C++ takes addresses of things without permission more readily than C does. Specifically: member functions, and references.
Because member functions require an implicit this parameter, it would be impossible to call them from an object declared register. In C, there is nothing prohibiting you from saying register struct X x;, so such language would have to be allowed in C++ [since C-compatibility is the whole reason the keyword even exists]. But if you prohibit calling member functions as well as taking addresses, that also covers the initial constructor call. In essence, it would not work on non-POD types. So you end up with one storage class specifier that is only valid for a small subset of the legal types, when all the rest can be used for anything.
You also could not create references to such objects, even though, technically, the compiler does not have to treat references as pointers. register int i; int& x; is not required to have space for two variables, but if you later do &x you end up with a pointer to i. So the initial construct has to be rendered illegal. While this seems like a non-issue, since references don't exist in C anyhow, returning to our previous point, POD types declared with the register specifier can no longer be copied. The compiler-provided copy constructor is of the form X::X(const X&) or X::X(X&) as appropriate.
So, in order to maintain C compatibility, they have to make register unique as a storage class specifier in that it does not apply to all types, and modify at least two different parts of the standard elsewhere [to specify that you can not create a reference to a variable declared with the register specifier, and to somehow work around the references for POD copying]. Or, they could just say "its okay to take the address" and let compilers decide whether or not to honor the requests. Something they were planning on doing anyhow.