2014-11-22 54 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