Reinterpret_cast rvalue and optimization

I am converting a bunch of code to use C ++ style styles (using -Wold-style-cast ). I do not completely sell its use for primitive variables, but I am new to C ++ style in general.

One problem arises in endian coding code. The current code looks like this:

 #define REINTERPRET_VARIABLE(VAR,TYPE) (*((TYPE*)(&VAR))) //... uint16_t reverse(uint16_t val) { /*stuff to reverse uint16_t*/ } int16_t reverse( int16_t val) { uint16_t temp = reverse(REINTERPRET_VARIABLE(val,uint16_t)); return REINTERPRET_VARIABLE(temp,int16_t); } 

Now, endianness does not care about subscription. Therefore, to reverse int16_t , we can treat it exactly like a uint16_t for reversal purposes. This offers the following code:

  int16_t reverse( int16_t val) { return reinterpret_cast<int16_t>(reverse(reinterpret_cast<uint16_t>(val))); } 

However, as described in this and, in particular, this question, reinterpret_cast requires a link or a pointer (if it does not throw itself at it). This allows:

  int16_t reverse( int16_t val) { return reinterpret_cast<int16_t&>(reverse(reinterpret_cast<uint16_t&>(val))); } 

This does not work because, as my compiler says, an external cast requires an lvalue. To fix this, you need to do something like:

  int16_t reverse( int16_t val) { uint16_t temp = reverse(reinterpret_cast<uint16_t&>(val)); return reinterpret_cast<int16_t&>(temp); } 

This is not much different from the source code, and indeed, the temporary variable exists for the same reason, but four questions were raised for me:

  • Why temporary, even necessary for reinterpret_cast ? I can understand that a mute compiler should have a temporary approach to support the muck of the REINTERPRET_VARIABLE pointer, but reinterpret_cast should just reinterpret the bit. Is it related to RVO or something?
  • Would it require a temporary refund to be related to performance, or maybe the compiler can understand that a temporary refund should really only be a return value?
  • The second reinterpret_cast looks like a return link. Since the return value of the function is not a reference, I am sure that everything is in order; the return value will be a copy, not a link. However, I still would like to know what link casting really even means? This is appropriate in this case, right?
  • Are there any other performance implications I should be aware of? I would suggest that reinterpret_cast would be, if at all possible, faster since the compiler does not need to figure out that the bits should be reinterpreted - am I just saying that they should?
+5
source share
2 answers

Since no one answered this with the help of legal facts after two years, I will answer it with my reasonable guesses.

  • Who knows. But this, apparently, is necessary, you guessed it. To avoid problems with a strict alias , it would be safer to use memcpy , which will be optimized by any compiler.

  • The answer to any such question should always profile it and check the disassembly. In the example you specified, for example. GCC optimizes it to :

     reverse(short): mov eax, edi rol ax, 8 ret 

    Which looks pretty optimal ( mov intended for copying from the input register, if you have built in your function and use it, you will see that it is completely absent).

  • This is a question of a language attorney. Probably has some useful semantic meaning. Do not worry about it. You haven't written the code like that.

  • Profile again. Maybe reinterpreting casting is hindering some optimizations. You should follow the same guidelines as for the strict anti-aliasing mentioned above.

+2
source
  • temp is required because when pronouncing, a lvalue is required to get the return value, as you discovered.

  • I expect the compiler to optimize it.

  • reinterpret_cast<T&>(x) same as * reinterpret_cast<T *>(&x) , this is an lvalue denoting the same memory location as x . Note that the type of an expression is never a reference; but the result of dropping to T& or using the * operator is an lvalue.

  • I would not expect any performance issues.

There is no strict problem with the alias with this particular piece of code, because it is allowed an alias of the integer type as a signed or unsigned variant of the same type. But you suggest that the codebase be full of reinterpretations, so you should keep track of severe -fno-strict-aliasing violations elsewhere, perhaps compile with -fno-strict-aliasing until it is parsed.

+1
source

Source: https://habr.com/ru/post/1201934/


All Articles