reinterpret_cast rvalue和优化

ima*_*ett 5 c++ casting

我正在转换一堆代码来使用C++风格的转换(借助于-Wold-style-cast).我并没有完全卖掉它用于原始变量的东西,但我是C++一般的新演员.

某些字节序转换代码中出现一个问题.当前代码如下所示:

#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);
}    
Run Code Online (Sandbox Code Playgroud)

现在,endianness并不关心签名.因此,为了逆转int16_t,我们可以将其视为uint16_t与逆转的目的完全相同.这表示代码如下:

 int16_t reverse( int16_t val) {
    return reinterpret_cast<int16_t>(reverse(reinterpret_cast<uint16_t>(val)));
}
Run Code Online (Sandbox Code Playgroud)

然而,如在描述,特别是这个问题,reinterpret_cast需要一个参考或指针(除非它浇铸到本身).这表明:

 int16_t reverse( int16_t val) {
    return reinterpret_cast<int16_t&>(reverse(reinterpret_cast<uint16_t&>(val)));
}
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为正如我的编译器告诉我的那样,外部演员想要一个左值.要解决此问题,您需要执行以下操作:

 int16_t reverse( int16_t val) {
    uint16_t temp = reverse(reinterpret_cast<uint16_t&>(val));
    return reinterpret_cast<int16_t&>(temp);
}
Run Code Online (Sandbox Code Playgroud)

这与原始代码没有太大的不同,实际上临时变量的存在也是出于同样的原因,但我提出了四个问题:

  1. 为什么一个临时甚至是必要的reinterpret_cast?我可以理解一个愚蠢的编译器需要一个临时的来支持指针的肮脏REINTERPRET_VARIABLE,但是reinterpret_cast应该只是重新解释位.这与RVO有什么冲突吗?
  2. 是否会要求临时性能下降,或者编译器是否可能发现临时值确实只是返回值?
  3. 第二个reinterpret_cast看起来像是在返回一个引用.由于函数返回值不是引用,我很确定这是可以的; 返回值将是副本,而不是引用.但是,我还是想知道什么样的参考甚至真的意味着?它在这种情况下,适当的,对不对?
  4. 我应该注意其他任何性能影响吗?我猜这reinterpret_cast会更快,因为编译器不需要弄清楚应该重新解释这些位 - 我只是它们应该?

ima*_*ett 2

由于两年内没有人用语言法律事实来回答这个问题,所以我将用我有根据的猜测来回答这个问题。

  1. 谁知道。但这显然是必要的,正如您所猜测的那样。为了避免严格别名的问题,使用它是最安全的memcpy,任何编译器都会正确优化它。

  2. 任何此类问题的答案始终是对其进行分析并检查反汇编。在您给出的示例中,例如 GCC会将其优化为

    reverse(short):
        mov     eax, edi
        rol     ax, 8
        ret
    
    Run Code Online (Sandbox Code Playgroud)

    这看起来非常理想(mov用于从输入寄存器进行复制;如果您内联函数并使用它,您会发现它完全不存在)。

  3. 这是一个语言律师问题。可能有一些有用的语义。别担心。从那以后你就再也没有写过这样的代码。

  4. 再次,简介。也许重新解释铸造会妨碍某些优化。您应该遵循与上面提到的严格别名相同的准则。