思考下面這一段code
void foo(int *i1, int *i2, int *res)
{
for(int i=0;i<10;i++){
*res += *i1 + *i2;
}
}
如果想要讓這段code變快,我們可能會想要這樣作
void foo(int *i1, int *i2, int *res)
{
int tmp=*i1 + *i2;
for(int i=0;i<10;i++)
*res += tmp;
}
}
但考慮到當呼叫端是如下就會發生問題:
foo(&v1,&v3,&v3);
我們永遠不知道caller 到底會丟什麼進來。因此,這樣的code是無法最佳化的。那如果是下面這個例子呢?
void foo(int32_t *i1, int32_t *i2, int64_t *res)
{
for(int i=0;i<10;i++){
*res += *i1 + *i2;
}
}
res的type是int64_t理論上應該就不會有問題了吧?如果呼叫端是:
foo(&v1,&v2,(int64_t *)&v3);
就會發生我們預期外的錯誤了。
為了讓上面這種狀況不會發生最佳化後的結果是我們預期外的,我們就啟用strict-aliasing來避免"不同型態"的指標指向相同的address除非兩種型態是類似的。例如:unsigned int可以alias int但不可以alias double。這麼我們就可以避免上述的情況發生。
在compile時如果我們開啟-O2,-O3,-Os或直接加上-fstrict-aliasing就會啟動fstrict-aliasing的選項。
- 簡單的方法避免Werror=strict-aliasing
假設我們的程式中需要作轉型例如
int foo() {
short a[2];
a[0]=1;
a[1]=0;
int *i=(int*)&a;
}
我們可以用union來表達
union union_a {
int i;
short s[2];
};
int foo() {
union union_a u;
u.i=1;
u.s[0]=1;
u.s[1]=0;
}
這樣就不會有warning: dereferencing type-punned pointer will break strict-aliasing rules的warning了。