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

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

错误提示如下,实际是个警告,但是由于编译器在警告出进行了优化,最后导致了严重的错误:
中文警告:提领类型双关的指针将破坏强重叠规则
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位。

转载于:https://my.oschina.net/dskfajoiewfcnlksdahf/blog/832183

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值