warning: dereferencing type-punned pointer will break strict-aliasing rules(转)

解释 GCC 从版本 3.x 开始引入严格别名规则(strict-aliasing)的原因及影响,并提供了解决违反此规则代码警告的几种方法,包括使用-fno-strict-aliasing 参数关闭优化、使用 union 结构进行类型转换等。着重强调了在现有代码中避免此类警告的重要性。
 

warning: dereferencing type-punned pointer will break strict-aliasing rules

  在 gcc 2.x 下编译没有任何 warning 信息的代码换到 gcc 3.x 版本下之后出现了类似的 warning 。原因是 gcc 3 引入了 strict aliasing 架构,当编译时使用了 -fstrict-aliasing 参数(该参数在使用了 -O2 , -O3, -Os 优化参数的情况下默认生效),而源代码中存在一些违反了 strict-aliasing 规则的地方的话,编译器就会对这部分代码提出 warning 。

  gcc 3 manual 对于 -fstrict-aliasing 参数的说明是:Allows the compiler to assume the strictest aliasing rules applicable to the language being compiled.  For C (and C++), this activates optimizations based on the type of expressions.  In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same.  For example, an "unsigned int" can alias an "int", but not a "void*" or a "double".  A character type may alias any other type.

  简而言之, 在该参数激活的情况下,编译器希望不同类型的对象不会指向同一个地址。比如像这段代码:

int retLen;
someSetFunc((unsigned long *)&retLen);
printf ("ret len = %d/n" ,retLen);

  由于 someSetFunc 的传入参数类型定义为 unsigned long ,所以需要进行这样的指针类型强制 cast 。但对于 -fstrict-aliasing 优化参数来说,这样的转换是有潜在问题的(但实际上可能并不会造成任何问题)。所以如果现有的源代码存在太多这样的类型强制转换的问题的话,对这些代码进行修改也许会是场噩梦。最简单的方法是使用 -fno-strict-aliasing 参数来关闭 gcc 的优化选项,代价是放弃了 strict-aliasing 编译优化可能带来的可执行代码的性能提升。当然也可以用 -Wno-strict-aliasing 来屏蔽相关的 warning 信息,但无论这些 warning 信息多么的无关紧要,总还是“疑似危险”,所以可能的话最好还是把所有的 warning 都消灭掉。

  消灭的方法也不算复杂,正如 gcc manual 所示的那样,可以是采用 union 的不同成员变量来完成类型的转换。上面那段代码可以改为:

union u_retLen
{
int retLen;
unsigned long ptr;
};
someSetFunc(&u_retLen.ptr);
printf ("ret len = %d/n" ,u_retLen.retLen);

  虽然会使源代码变得丑陋,但对于大部分已有的源代码来说,这可能是改动最小的方案了。而对于新写的代码来说,如何更好的设计函数的入口参数(比如使用 void*)可能才是需要去思考的问题了。

arm-nuvoton-linux-uclibceabi-gcc -std=c99 -Wall -Wextra -Wpedantic -O3 -DCO_SINGLE_THREAD -DCO_CONFIG_DEBUG=0xFFFF -DNDEBUG -I. -I./CANopenLinux -I./CANopenLinux/CANopenNode -I./CANopenLinux/CANopenNode/301 -I./CANopenLinux/CANopenNode/example -c CANopenLinux/CO_driver.c -o CANopenLinux/CO_driver.o In file included from ./CANopenLinux/CO_driver_target.h:44:0, from ./CANopenLinux/CANopenNode/301/CO_driver.h:27, from CANopenLinux/CO_driver.c:36: ./CANopenLinux/CO_error.h:111:21: error: field ‘timestamp’ has incomplete type struct timespec timestamp; /**< listen only mode started at this time */ ^ In file included from ./CANopenLinux/CANopenNode/301/CO_driver.h:27:0, from CANopenLinux/CO_driver.c:36: ./CANopenLinux/CO_driver_target.h:245:21: error: field ‘timestamp’ has incomplete type struct timespec timestamp; /* time of reception of last message */ ^ CANopenLinux/CO_driver.c: In function ‘CO_CANread’: CANopenLinux/CO_driver.c:764:13: error: dereferencing pointer to incomplete type *timestamp = ((struct timespec*)CMSG_DATA(cmsg))[0]; ^ CANopenLinux/CO_driver.c:764:35: error: invalid use of undefined type ‘struct timespec’ *timestamp = ((struct timespec*)CMSG_DATA(cmsg))[0]; ^ CANopenLinux/CO_driver.c:764:61: error: dereferencing pointer to incomplete type *timestamp = ((struct timespec*)CMSG_DATA(cmsg))[0]; ^ CANopenLinux/CO_driver.c:766:13: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] dropped = *(uint32_t*)CMSG_DATA(cmsg); ^ CANopenLinux/CO_driver.c: In function ‘CO_CANrxFromEpoll’: CANopenLinux/CO_driver.c:843:33: error: storage size of ‘timestamp’ isn’t known struct timespec timestamp; ^ CANopenLinux/CO_driver.c:843:33: warning: unused variable ‘timestamp’ [-Wunused-variable] make: *** [Makefile:155: CANopenLinux/CO_driver.o] Error 1
11-11
arm-nuvoton-linux-uclibceabi-gcc -std=c99 -Wall -Wextra -Wpedantic -O3 -DCO_SINGLE_THREAD -DCO_CONFIG_DEBUG=0xFFFF -DNDEBUG -I. -I./CANopenLinux -I./CANopenLinux/CANopenNode -I./CANopenLinux/CANopenNode/301 -I./CANopenLinux/CANopenNode/example -c CANopenLinux/CO_driver.c -o CANopenLinux/CO_driver.o In file included from ./CANopenLinux/CO_driver_target.h:57:0, from ./CANopenLinux/CANopenNode/301/CO_driver.h:30, from CANopenLinux/CO_driver.c:39: ./CANopenLinux/CO_error.h:111:21: error: field ‘timestamp’ has incomplete type struct timespec timestamp; /**< listen only mode started at this time */ ^ In file included from ./CANopenLinux/CANopenNode/301/CO_driver.h:30:0, from CANopenLinux/CO_driver.c:39: ./CANopenLinux/CO_driver_target.h:258:21: error: field ‘timestamp’ has incomplete type struct timespec timestamp; /* time of reception of last message */ ^ CANopenLinux/CO_driver.c: In function ‘CO_CANread’: CANopenLinux/CO_driver.c:767:13: error: dereferencing pointer to incomplete type *timestamp = ((struct timespec*)CMSG_DATA(cmsg))[0]; ^ CANopenLinux/CO_driver.c:767:35: error: invalid use of undefined type ‘struct timespec’ *timestamp = ((struct timespec*)CMSG_DATA(cmsg))[0]; ^ CANopenLinux/CO_driver.c:767:61: error: dereferencing pointer to incomplete type *timestamp = ((struct timespec*)CMSG_DATA(cmsg))[0]; ^ CANopenLinux/CO_driver.c:769:13: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] dropped = *(uint32_t*)CMSG_DATA(cmsg); ^ CANopenLinux/CO_driver.c: In function ‘CO_CANrxFromEpoll’: CANopenLinux/CO_driver.c:846:33: error: storage size of ‘timestamp’ isn’t known struct timespec timestamp; ^ CANopenLinux/CO_driver.c:846:33: warning: unused variable ‘timestamp’ [-Wunused-variable] make: *** [Makefile:155: CANopenLinux/CO_driver.o] Error 1 在gcc4.8.4上编译错误
最新发布
11-11
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值