Cal*_*ius 15 c strict-aliasing
以下面的代码片段为例:
*pInt = 0xFFFF;
*pFloat = 5.0;
Run Code Online (Sandbox Code Playgroud)
由于他们是int
和float
指针,编译器将假定他们不这样做别名,例如可以交换.
现在让我们假设我们用这个来加强它:
*pInt = 0xFFFF;
*pChar = 'X';
*pFloat = 5.0;
Run Code Online (Sandbox Code Playgroud)
因为char*
允许别名,它可能指向*pInt
,所以赋值*pInt
不能超出赋值*pChar
,因为它可以合法地指向*pInt
并将其第一个字节设置为'X'.类似地pChar
可以指向*pFloat
,*pFloat
在char赋值之前不能移动赋值,因为代码可能打算通过重新分配来取消先前字节设置的效果*pFloat
.
这是否意味着我可以通过编写和读取char*
来为重新排列和其他严格的别名相关优化创建障碍?
在编译器无法知道指针变量是否为另一个指针的别名时,指针别名通常很有意义.与编译位于与调用者不同的翻译单元中的函数的情况一样.
void func (char* pChar, float* pFloat)
{
*pChar = 'X';
*pFloat = 5.0;
}
Run Code Online (Sandbox Code Playgroud)
这里的pFloat
分配确实不能在分配之前排序pChar
,因为编译器不能扣除pChar
不指向同一位置的分配pFloat
.
但是,在面对这种情况时,编译器可以(并且可能会)添加运行时检查以查看地址是否指向重叠内存.如果他们这样做,那么代码必须按给定的顺序排序.如果不是,则可以重新组织和优化代码.
这意味着只有在指针实际上为别名/指向重叠内存的情况下才会获得类似内存屏障的行为.如果没有,那么关于指令排序的所有赌注都将被取消.所以这可能不是你应该依赖的机制.