2014-11-22 43 views
1

陣列我有這樣的功能:嚴格混疊和在C

static void doSomething(int16_t array[256], int16_t mask, uint8_t skip){ 
    uint16_t storage = array[skip]; 
    uint64_t* array1=(uint64_t*)(array); 
    uint64_t mask1 =0; 
    uint16_t* Lmask=(uint16_t*)&mask1; 
    Lmask[0]=mask; 
    Lmask[1]=mask; 
    Lmask[2]=mask; 
    Lmask[3]=mask; 
    int k; 
    for (k =0 ; k < 64; k++) { 
     array1[k]&=mask; 
     array[skip]=storage; 
     if(hasZero(array1[k])){ 
     ... 
     } 
    } 

應該採取的16位整數的數組,在其上施加一個掩模,並檢查,是否它包含一個16位的整數等於零那不在跳過位置,如果是的話,做一些事情。它一切正常,直到使用-O2優化(-O1,-Os正常運行)。

該函數被稱爲數十萬次,因此它不能使用16位掩碼和16位數組。我想,問題是,這個代碼打破了嚴格的別名規則。有什麼辦法可以對編譯器說,array1和array使用相同的內存位置,因此它在評估if語句之前不能忽略array[skip]=storage;(我嘗試過union,但是沒有成功,它完全一樣如現在)?或者有沒有其他方法可以做到這一點,它不會違反這條規則?

+0

但是你真的需要O2嗎? – MightyPork 2014-11-22 12:45:49

+0

就像我這樣做是不幸的,整個項目都是使用-O2編譯的,我不能反對它。 – Rasty 2014-11-22 12:47:43

+0

您的文本顯示'g ++'但您的q被標記了[tag:C] – 2014-11-22 12:49:33

回答

2

是的,這違反了嚴格的別名,通過使用uint16_tuint64_t左值來讀取相同的存儲區域。

gcc的快速修復是使用-fno-strict-aliasing

可靠的修復方法是將代碼重寫爲不包含任何別名違規。這看起來似乎更加隱晦,但理論上編譯器會看到發生了什麼,並在編寫正確的代碼時生成最佳程序集。

+0

是的,我想這樣做,但是如何在使用64位數字的同時做到這一點呢?如果我放棄它,它當然會變慢,這是我想避免的。 – Rasty 2014-11-22 13:02:00

+0

「它當然會更慢」 - 在做出這個假設之前(或者比較彙編)進行基準測試 – 2014-11-22 13:12:08

+0

好吧,我已經試過了,而且看起來比預期的要慢。 – Rasty 2014-11-22 13:15:10