- 相关推荐
C 语言声明与定义不一致导致的问题
我们在写代码的时候,往往只注意函数的实现,对函数的声明重视不足。下面是小编为大家带来的C 语言声明与定义不一致导致的问题,欢迎阅读。
C 语言声明与定义不一致导致的问题
最近项目代码需要从mips平台移植到x86平台,这是公司产品第一次采用x86平台。之前项目很紧,所以很多代码都没有考虑移植性问题,因此移植的时候遇到了不少问题。前几天才解决了位序(也叫比特序,与字节序不同)问题,今天又遇到了一个比较隐蔽的C语言问题,在这里记录一下,告诫自己,也告诫各位同行,避免犯这样的错误。至于位序问题,以后应该会再另写一篇文章来说明。
原本在mips平台上运行良好的代码,移植到了x86平台,结果却不对了,我们仔细分析了代码,没发现什么可疑的地方,而且我之前为了优化那段代码,单独把那段代码抽出来测试过。我抽出来的代码在两个平台里得出的都是一样的结果。我对比了代码,实现的地方没有任何改动,照理说不应该出现这种情况的。不过根据打印出来的值,我注意到了一种情况,在x86平台里的结果值只有16位,但在mips平台里的结果值有32位,并且低16位的值与x86平台下的值一样。最后,我查看了声明该函数的头文件,才发现头文件里函数的.声明与C文件里的实现返回值不一致!
问题可以简化成下面的代码:
//crc.c
//注意,此处没有包含crc.h这个头文件!
unsigned int get_crc(void)
{
return 0x12345678;
}
//crc.h
unsigned short get_crc(void);
//main.c
#include
#include "crc.h"
int main(int argc, char *argv[])
{
unsigned int crc = get_crc();
printf("crc:%x ", crc);
return 0;
}
编译执行: gcc -Wall -o test main.c crc.c //好吧,-Wall也没办法报错
在x86平台下输出:5678
我又分别在mips平台和powerpc平台下编译执行了这段代码,同样没警告或者报错。在mips平台下输出:12345678,在powerpc平台下输出:12345678
在简化的代码里,大家很容易就能看出是get_crc这个函数的声明和定义(实现)不一致导致的问题,但在庞大的项目文件里,可能就没那么容易看出问题所在了。
我们在写代码的时候,往往只注意函数的实现,对函数的声明重视不足。在Linux平台下,我们喜欢用cscope+ctags+vim来写代码,修改或者浏览代码的时候也喜欢跳到函数定义处,变量声明处,却很少关注函数声明,导致修改代码之后声明和定义不一致的情形。
这并不只是程序新手才会出现的问题,工作几年的程序员也可能会犯这样的错误,出现问题的这段代码,就是出自一个已经工作了四年的同事之手。
也正是在这个时候,我才发现,我们之前的代码是有问题的,只是所谓的“得到了正确的结果”。
我起先认为对于这种情况,是个编译器未定义形为,不同gcc版本对这种情况的处理可能不一样,但我进行了一些测试,发现情况比我想象中的复杂。在powerpc平台,gcc版本是3.3.x,mips平台,gcc版本是4.3.x,在x86平台,有两个版本的编译器,分别为4.1.x(centos),4,6.x(ubuntu)执行情况是mips平台和powerpc平台一样,都是12345678,x86平台下均为5678。mips和powerpc都是大端,x86是小端,至令我没办法判断真正的问题在哪,是编译器版本原因还是与大小端有那么点关系。还望知道的朋友不吝赐教。
此外,我还测试了对于变量的情况,发现对于变量的处理,各个gcc版本不同平台都是一致的,当然,由于大小端的关系,输出结果会不同。大家有兴趣可以试一下。
说了那么多,只是想说明这个隐蔽的错误大家一不小心就很容易犯,而且后果也比较严重,得找到方法避免。解决办法很简单,那就是通过把函数声明(原型)放在头文件中,而函数定义则放在另一个包含了该头文件的源文件中。这样编译器就能发现不一致的情况从而报错提醒我们。这个问题在《C专家编程》8.5节有论述。
【C 语言声明与定义不一致导致的问题】上海花千坊相关的文章:
C语言变量定义07-29
C语言宏定义07-01
C语言函数的定义07-13
C语言数组的定义及引用08-05
C语言宏定义技巧09-03
C语言的宏定义分析09-10
C语言变量的定义与使用09-05
C语言声明的语法04-26
C语言预定义宏用法10-06
关于C语言宏定义的技巧09-21