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语言的移位操作符使用方法,希望能给大家带来帮...
-
C语言考试机试经验三部曲
全国计算机等级考试的持续升温,至使全国计算机等级考试证书已成为国家公务员、国家企事业单位工作人员、公司员工等上岗、加薪、提拔的必备条件。以下是本站小编整理的C语言考试机试经验三部曲,希望可以为您的考试带来帮助!第一部:备考篇名将不打无准备之仗,复习备...
-
二级C语言考试复习五要点
综观近几年全国计算机等级二级基础部分和C语言程序设计的题目,笔试中大多数考题是与大纲要求的基本内容一致的,难度不高,但内容十分广泛,应牢固掌握。以下是小编为您带来的二级C语言考试复习五要点,感谢您的阅读!一、了解试卷,胸中有数综观近几年全国计算机等级二级...
-
关于C语言精选模拟练习题
C语言是一个有结构化程序设计、具有变量作用域(variablescope)以及递归功能的过程式语言。下面是小编为大家整理的关于C语言精选模拟练习题,欢迎参考~5:请编写一个函数fun,它的功能是:比较两个字符串的长度,(不得调用c语言提供的`求字符串长度的函数),函数返回较长...