c语言中的严格别名和数组

c语言中的严格别名和数组,c,arrays,strict-aliasing,C,Arrays,Strict Aliasing,我有这样一个函数: 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; L

我有这样一个函数:

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])){
        ...
        }
    }
static void doSomething(int16\u t数组[256],int16\u t掩码,uint8\u t skip){
uint16_t存储=数组[跳过];
uint64_t*数组1=(uint64_t*)(数组);
uint64_t mask1=0;
uint16_t*Lmask=(uint16_t*)和mask1;
Lmask[0]=掩码;
Lmask[1]=掩码;
Lmask[2]=掩码;
Lmask[3]=掩码;
int k;
对于(k=0;k<64;k++){
阵列1[k]&=掩模;
数组[跳过]=存储;
if(hasZero(array1[k])){
...
}
}
它应该采用一个16位整数数组,在其上应用一个掩码,并检查它是否包含一个不在跳过位置的等于零的16位整数,如果是,则执行一些操作。在使用优化-O2(-O1,-Os正常工作)之前,一切都可以正常工作


该函数被调用了数百万次,因此它不能使用16位掩码和16位数组,因为这是有效的。我想,问题是,这段代码违反了严格的别名规则。有没有办法,对编译器说,数组1和数组使用相同的内存位置,因此它不能忽略
数组[skip]=storage;
在评估if语句之前(我尝试了union,但是没有成功,它的操作与现在完全相同)?或者是否有其他方法可以这样做,这样它就不会违反此规则?

是的,这违反了严格的别名,使用
uint16\u t
uint64\u t
左值来读取相同的存储区域

gcc的一个快速修复方法是使用
-fno严格别名


一个可靠的解决方法是重写代码,使其不包含任何别名冲突。这一点起初可能看起来更神秘,但理论上,如果您编写正确的代码,编译器将看到发生了什么,并生成最佳程序集。

但您真的需要O2吗?尽管我很不幸,整个项目都是使用-O2编译的,我不能做任何事情你的文本说“代码> G++<代码>,但是如果使用了代码> G++<代码>,你的Q被标记,然后它是C++代码,应该被标记为C++,用于这个站点,我在GCC上测试过它,它显示出同样的行为,所以我把G++部分从主文本中去掉,以免混淆。是的,我想做,但是H如何在保留64位数字的工作时做到这一点?如果我不使用它,它当然会变慢,这是我希望避免的。“它当然会变慢”-在做出此假设之前对其进行基准测试(或比较汇编)我已经尝试过了,但它似乎比预期的要慢。也许你的代码是错误的;也许用你试图询问的代码开始一个新的问题,如何提高速度,但是保留了原来的问题,是否可以指示编译器不要遗漏它,如果可能的话,在代码内部,因为我不是那个人做最后的编译。