我正在转换一堆代码来使用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)
这与原始代码没有太大的不同,实际上临时变量的存在也是出于同样的原因,但我提出了四个问题:
reinterpret_cast?我可以理解一个愚蠢的编译器需要一个临时的来支持指针的肮脏REINTERPRET_VARIABLE,但是reinterpret_cast应该只是重新解释位.这与RVO有什么冲突吗?reinterpret_cast看起来像是在返回一个引用.由于函数返回值不是引用,我很确定这是可以的; 返回值将是副本,而不是引用.但是,我还是想知道什么样的参考甚至真的意味着?它是在这种情况下,适当的,对不对?reinterpret_cast会更快,因为编译器不需要弄清楚应该重新解释这些位 - 我只是说它们应该?由于两年内没有人用语言法律事实来回答这个问题,所以我将用我有根据的猜测来回答这个问题。
谁知道。但这显然是必要的,正如您所猜测的那样。为了避免严格别名的问题,使用它是最安全的memcpy,任何编译器都会正确优化它。
任何此类问题的答案始终是对其进行分析并检查反汇编。在您给出的示例中,例如 GCC会将其优化为:
reverse(short):
mov eax, edi
rol ax, 8
ret
Run Code Online (Sandbox Code Playgroud)
这看起来非常理想(mov用于从输入寄存器进行复制;如果您内联函数并使用它,您会发现它完全不存在)。
这是一个语言律师问题。可能有一些有用的语义。别担心。从那以后你就再也没有写过这样的代码。
再次,简介。也许重新解释铸造会妨碍某些优化。您应该遵循与上面提到的严格别名相同的准则。
| 归档时间: |
|
| 查看次数: |
850 次 |
| 最近记录: |