简体   繁体   中英

C++ how does cast with reference work?

Can anyone explain what's happening in the following code?

char cd[1024];
unsigned short int & messageSize =reinterpret_cast<unsigned short int&>(*cd);

does it take the first 2 char of cd by reference and cast it to a 16 bit int? when I remove the '&', the compiler complains about cannot cast from char to unsigned short int.

unsigned short int messageSize =reinterpret_cast<unsigned short int>(*cd);

The "intuitive" meaning of reinterpret_cast is "take a sequence of bits and treat it as if that sequence of bits has a different type". That is not possible to do for types char and unsigned short , because they have different width.

As for the first case, the intuition is: reinterpret_cast treats lvalue reference as if it was a pointer to the type it refers (and applies mentioned conversion to that pointer).

Formally, the standard says:

4.2 Array-to-pointer conversion [conv.array]

  1. An lvalue or rvalue of type “array of NT” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.

and:

5.3.1 Unary operators [expr.unary.op]

  1. The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. If the type of the expression is “pointer to T”, the type of the result is “T”.

So, after dereferencing *cd we will get an lvalue of type char (same as if you wrote cd[0] ).

5.2.10 Reinterpret cast [expr.reinterpret.cast]

  1. A glvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast . The result refers to the same object as the source glvalue, but with the specified type. [ Note: That is, for lvalues, a reference cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with the built-in & and * operators (and similarly for reinterpret_cast<T&&>(x) ). — end note ] No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.

That means, you have got something like

*reinterpret_cast<unsigned short *>(&cd[0])

But what is perhaps more important than all the above:

3.10 Lvalues and rvalues [basic.lval]

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

  • the dynamic type of the object,
  • a cv-qualified version of the dynamic type of the object,
  • ...
  • a char or unsigned char type.

That is, binding a "reference to char" to an object of type "unsigned short" is ok. But doing vise-versa (ie, as in your example) is sort-of-not-ok, because accessing such reference would invoke undefined behavior.

Cast with reference is different from the same cast without reference in one thing - cast without reference creates a new temporary object, while cast with reference changes the type of the already existing object. This matters in many cases, for example, in your case, since you assigning a result to a non-const reference. Non-const references can not be inialized with temporary objects.

On a side note, you know that what you are doing here is a violation on type aliasing rule, and is yields undefeined behaviour?

unsigned short int & messageSize means that messageSize is a variable of type unsigned short int , and the memory area where that variable will be stored shall be given as initializer.

The initializer =reinterpret_cast<unsigned short int&>(*cd) says: take the memory at the location being pointed to by cd , and pretend it contains a unsigned short int .

The result is that if you try to read and write messageSize , then you will try to read and write a unsigned short int in a memory location that contains something else. This causes undefined behaviour.

There are a few situations in which it is OK to pretend a memory location contains an object that it actually doesn't; this is not one of them.

If your compiler is not performing aliasing optimizations then it might appear as if your code "works" for now. However the code is broken.

reinterpret_cast<unsigned short int&>(*cd);

类似于

*reinterpret_cast<unsigned short int*>(cd);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM