违反严格的别名规则

在下面的代码中,让我们假设 floatuint32_t 具有相同的大小。

void fun(uint32_t* u, float* f) {
    float a = *f
    *u = 22;
    float b = *f;
    print("%g should equal %g\n", a, b);
}

uf 具有不同的基类型,因此编译器可以假设它们指向不同的对象。在 ab 的两次初始化之间*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);

我们违反了严格的别名规则。然后行为变得不确定。输出可以如上所述,如果编译器优化了第二次访问,或者完全不同的东西,那么你的程序最终会处于完全不可靠的状态。