warning: dereferencing pointer ** does break strict-aliasing rules

来源:互联网 发布:windows命令 编辑:程序博客网 时间:2024/06/06 12:46

记录一次编译开启优化导致的错误

错误提示如下,实际是个警告,但是由于编译器在警告出进行了优化,最后导致了严重的错误:
中文警告:提领类型双关的指针将破坏强重叠规则
warning: dereferencing pointer ‘p’ does break strict-aliasing rules


警告产生背景:

警告是在进行代码移植时遇到的,原代码运行在32位系统,并且gcc版本较低,具体是哪一版本不知道,接手代码后我直接开始移植到64位系统,gcc版本4.4。经过漫长的修改不得不吐槽一下,移植有多蛋疼,比如之前的代码很多指针强转为32位整型,要3000多行代码一行一行检查类型改成64位的,同时修改后的代码还要兼容32位。移植代码问题不说,主要针对这个警告,在移植过程中,我在两个系统中测试过代码,一个是win10系统带的bash,Ubuntu14.04的内核,GCC版本4.8.4,另一个是开发环境Linux系统,GCC版本4.4。在Bash on Ubuntu on Windows下编译运行没问题不会警告,运行正常。在开发环境下会出现警告,程序运行进入死循环。后来发现,Makefile里面加了-O2优化。这种莫名其妙的问题检查了一天代码没发现原因,估计可能是编译器优化的问题,毕竟这个代码是32位老系统移植过来,编译出现问题是非常有可能,所以取消-O2优化,编译通过,没有警告,运行正常。

警告分析:

该警告出现的情况是,两个不同类型(size不同)的指针指向了同一内存区域,很明显出现这种问题必然是有错误的,这个和类型强制转换应该是不同的。uint64_t sum = 0;uint32_t *sum_p = (uint32_t *)∑sum本身是64位变量,sum_p指针又是指向32位变量,就出现同一个起始地址对应两个类型长度不同的变量。编译器优化会对这个地方做处理,具体处理不明。

警告处理:

处理方法很简单,错误代码的目的很明显:    uint64_t sum = 0;uint32_t *sum_p = (uint32_t *)∑开发者想法应该是使用sum_p去分别读取64位sum的前后32字节数据,sum_p[0], sum_p[1]比如这样,这种运用在大数加法中常用到,两个1024位大数进行加法,以32位为基准进行循环加法,每次相加可能会有进位操作,和保存在64位中,不会溢出,同时能提取进位后的值进行后续的加法运算。总之错误代码目的就是把一个64位整型,分成前后两个32位整型分别读取。这听起来和C语言联合体功能一样,的确,解决办法就是使用联合体:union sums{    uint32_t sum_p;    uint64_t sum;};union sums add;add.sum = val;add.sum_p自然就是前32位,将add.sum移位就可以得到后32位。
0 0
原创粉丝点击