interpret_cast右值和优化
reinterpret_cast rvalue and optimization
我正在转换一堆代码以使用C++风格的强制转换(在-Wold-style-cast
的帮助下)。我并不完全相信它对基元变量的使用,但我对C++风格的转换一般来说还是个新手。
在某些endian转换代码中出现一个问题。当前代码如下:
#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);
}
现在,endianness并不关心签名性。因此,为了反转int16_t
,我们可以像对待uint16_t
一样对待它。这建议代码如下:
int16_t reverse( int16_t val) {
return reinterpret_cast<int16_t>(reverse(reinterpret_cast<uint16_t>(val)));
}
然而,正如本问题中所描述的,特别是本问题中,reinterpret_cast
需要一个引用或指针(除非它强制转换为自身)。这表明:
int16_t reverse( int16_t val) {
return reinterpret_cast<int16_t&>(reverse(reinterpret_cast<uint16_t&>(val)));
}
这不起作用,因为正如我的编译器告诉我的那样,外部强制转换需要一个左值。要解决此问题,您需要执行以下操作:
int16_t reverse( int16_t val) {
uint16_t temp = reverse(reinterpret_cast<uint16_t&>(val));
return reinterpret_cast<int16_t&>(temp);
}
这与原始代码没有太大区别,事实上,临时变量的存在也是出于同样的原因,但我提出了四个问题:
- 为什么
reinterpret_cast
需要临时的?我可以理解一个愚蠢的编译器需要一个临时的来支持REINTERPRET_VARIABLE
的指针脏,但reinterpret_cast
应该只是重新解释位。这是与RVO冲突还是什么 - 要求临时值会导致性能损失吗?或者编译器可能会发现临时值实际上应该只是返回值吗
- 第二个
reinterpret_cast
看起来像是在返回一个引用。由于函数返回值不是引用,我确信这是可以的;返回值将是一个副本,而不是引用。然而,我仍然想知道铸造引用的真正含义是什么?在这种情况下是合适的,对吧 - 我是否应该意识到其他绩效影响?我想
reinterpret_cast
会更快,如果有什么不同的话,因为编译器不需要弄清楚比特应该被重新解释——我只是告诉它们应该重新解释
-
temp
是必需的,因为&
(的地址)运算符在下一行应用于它。此运算符需要一个左值(要获取其地址的对象)。 -
我希望编译器能对它进行优化。
-
reinterpret_cast<T&>(x)
与* reinterpret_cast<T *>(&x)
相同,它是指定与x
所占据的相同存储位置的左值。请注意,表达式的类型从来都不是引用;但是转换为T&
或使用*
运算符的结果是左值。 -
我预计不会有任何性能问题。
这段代码没有严格的别名问题,因为允许将整数类型别名为同一类型的有符号或无符号变体。但您建议代码库中充满了重新解释的强制转换,因此您应该注意其他地方的严格混叠冲突,也许可以使用-fno-strict-aliasing
进行编译,直到它被解决为止。
由于两年来没有人用语言律师的事实来回答这个问题,我将用我有根据的猜测来回答。
-
谁知道呢。但正如你所推测的那样,这显然是必要的。为了避免严格混叠的问题,使用
memcpy
是最安全的,任何编译器都会对其进行正确优化。 -
任何此类问题的答案都是对其进行分析并检查拆卸情况。在您给出的示例中,例如GCC会将其优化为:
reverse(short): mov eax, edi rol ax, 8 ret
这看起来非常优化(
mov
用于从输入寄存器复制;如果您内联函数并使用它,您会发现它完全不存在)。 -
这是一个语言律师的问题。可能有一些有用的语义。别担心。从那以后,你还没有写过这样的代码。
-
再次,简介。也许重新解释选角会妨碍某些优化。您应该遵循与上面提到的严格别名相同的准则。
- 空基优化子对象的地址
- 如何理解C++标准N3337中的expr.const.cast子句8
- 关闭||运算符优化
- C++Cast运算符过载
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 返回值优化:显式移动还是隐式
- 人脸跟踪arduino代码的优化
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 纯函数,为什么没有优化
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 如何以优化的方式同时迭代两个间距不相等的数组
- 小字符串优化(调试与发布模式)
- 浮点定向舍入和优化
- Visual Studio 调试优化如何工作?
- 为什么开关的优化方式与 c/c++ 中的链接不同?
- 线性优化目标函数中的绝对值
- GCC 会优化内联访问器吗?
- gcc 如何优化此循环?
- 如何防止 CUDA-GDB 中的<优化输出>值
- 为什么我的程序在 O0 和 O2 的优化级别返回不同的结果