違反嚴格的別名規則
在下面的程式碼中,讓我們假設 float
和 uint32_t
具有相同的大小。
void fun(uint32_t* u, float* f) {
float a = *f
*u = 22;
float b = *f;
print("%g should equal %g\n", a, b);
}
u
和 f
具有不同的基型別,因此編譯器可以假設它們指向不同的物件。在 a
和 b
的兩次初始化之間*f
不可能發生變化,因此編譯器可能會將程式碼優化為相當於
void fun(uint32_t* u, float* f) {
float a = *f
*u = 22;
print("%g should equal %g\n", a, a);
}
也就是說,*f
的第二次載入操作可以完全優化。
如果我們正常呼叫此函式
float fval = 4;
uint32_t uval = 77;
fun(&uval, &fval);
一切順利,等等
4 應該等於 4
列印出來。但如果我們作弊並傳遞相同的指標,轉換後,
float fval = 4;
uint32_t* up = (uint32_t*)&fval;
fun(up, &fval);
我們違反了嚴格的別名規則。然後行為變得不確定。輸出可以如上所述,如果編譯器優化了第二次訪問,或者完全不同的東西,那麼你的程式最終會處於完全不可靠的狀態。