返回值类型为unsigned long long的函数永远返回为0的问题解决
来源:互联网 发布:php完整项目源码 编辑:程序博客网 时间:2024/05/17 04:06
今天帮同事解决了一个很奇怪的问题,一个定义返回值为unsigned long long的函数在实际调用中竟然永远返回0,就算你在此函数内返回任意整数调用者获得的都是0.
硬件平台为PPC8313,操作系统为嵌入式Linux,编译器为g++的交叉编译器,版本为4.2.2.
环境比较复杂,但问题简化后总共涉及三个文件,liba.h定义一些函数接口和liba.cpp实现liba.h定义的函数接口,这两个文件在编译后生成一个名字为liba.a的静态库,main.cpp调用liba.a内的接口,最后和liba.a一起链接生成名为test的可执行文件。
三个文件代码简化如下:
liba.h内容如下:
/* liba.h */#pragma once#ifdef __cplusplusextern "C" {#endif /* end of defined __cplusplus */unsigned long long GetSize();#ifdef __cplusplus}#endif /* end of defined __cplusplus *//* end of liba.h */
liba.cpp内容如下:
/* liba.cpp */#include <stdio.h>#include "liba.h"using namespace std;unsigned long long GetSize(){unsigned long long ret = 123456;printf("In function GetSize() ret = %llu\n",ret);return ret;}/* end of liba.cpp */
main.c内容如下:
/* main.c */ #include <stdio.h>//#include "liba.h" /* 这里没有引用liba.h,问题就出在这 */int main(int argc, char** argv){unsigned long long temp = GetSize();printf("In main() GetSize() = %llu\n",temp);return 0;}/* end of main.c */
我一般喜欢bjam来编写编译规则,jamroot.jam内容如下:
# jamroot.jamlib a : liba.cpp ;exe test : main.c a ;
第一行“#”表示注释,第二行表示依赖liba.cpp编译生成liba库,第三行表示依赖main.c和liba生成名字为test的可执行文件。(bjam可以简单地构建简单的目标,可管理地构建复杂的目标,如此可见一斑,确实够强悍的。)
设置好bjam交叉编译环境,在Linux下执行:bjam toolset=gcc-ppc8313 link=static即可生成相应的库和可执行文件。
传到8313板上,chmod后执行,竟然输出:
In function GetSize() ret = 123456In main() GetSize() = 0
不管你如何修改ret的值,也不管你是debug版本和release版本(甚至换其它编译链接参数),在main函数内获得GetSize()的返回值永远为0。
几个同事搞了好几天,一直都不知道是什么原因,奇怪的是同样一份代码,使用X86的g++没有任何问题,在PPC880和PPC8548、ARM Cortex A8等硬件平台下均没有任何问题,但在PPC8313下却有问题。此问题之玄乎竟成了我们部门的疑难杂症。后来同事求助于我,刚好我手上的东西不是很急,也刚好想研究一下这种疑难杂症(毕竟有问题才能学到真东西),所以我叫他发代码给我研究一下。经过一番试验后,同事的描述都是对的,在X86下没有任何问题,但在某块PPC8313开发板上竟然有这样的问题,也暂时把我难住了好一会,首先怀疑交叉编译器问题,但同样的一个可执行文件在同为PPC8313的板上竟然有些执行正确有些执行不正确;再就怀疑这块板内核和文件系统不同,经过跟同为PPC8313的正常的板信息对比后,都是一样的,取消了这个怀疑;后来我又怀疑是不是这块板对unsigned long long类型支持有问题,经过写测试程序和改变类型,就算我把代码里面的unsigned long long改为int类型,有问题的板同样返回0;我开始从编译过程来查找问题了,因为同事的实际代码比较多,编译GetSize()函数时有个很不明显的警告:
warning: implicit declaration of function ‘GetSize’
以我多年“种田”的经验,在这里肯定是有问题的,出现这种警告一般就两个原因:
1:没有把函数所在的源文件生成.o目标文件;
2:在函数所在的源文件中调用了,但是引用相关的头文件进行声明。
同事的代码一看就是第二种原因,给代码增加相应头文件进行声明后编译警告消除,然后交叉编译放板上,奇迹发生了,竟然输出了正确的结果。
用相应的objdump工具查看汇编代码,同个版本(debug/release)GetSize()函数生成生成的汇编代码完全一模一样,但在函数调用返回后的处理有点不同,这个不同是造成这个问题的根本原因。
得到教训:
1:头文件不是可有可无的。gcc的检查比较弱(虽然文件名为cpp但文件中使用extern ”C“),不引用头文件但有链接实现的库照样可以链接成功。如果不引用头文件,编译链接可能没问题,但在使用中可能会遇到很奇怪的问题,就如我们遇到的这个疑难杂症一样,编写代码时一定要注意。
2:编译代码不能忽视任何的警告信息,最好保持代码编译的零警告,窗户有个洞如果一直都不堵的话这个洞会越来越大的。
3:错误发现的越早越好,能在编译时发现的错误,不要拖到运行时;能在编辑时发现的错误,不要拖到编译时。
4:要有正确的编码规范。
5:最好在开发中使用一些静态代码检查工具辅助开发,如cppcheck和pc-link等都是不错的静态代码检查工具。
- 返回值类型为unsigned long long的函数永远返回为0的问题解决
- 后台date类型转换为json字符串时,返回前台页面的是long time值问题解决
- unsigned long类型转换为CString出现的问题
- unsigned long类型转换为CString出现的问题
- 编写四个重载函数Double(x),返回值为输入参数的两倍;参数类型分别为int,long,float,double,返回值类型与参数类型一致。
- spring mvc4返回的json日期为Long的解决方案
- Spring mvc4返回的json日期为Long的解决方案
- springMVC返回的json日期为Long的格式化
- spring mvc返回的json日期为Long的解决方案
- mybatis查询的返回类型为基础类型(int、long等),但结果为null时的异常解决
- Hibernate的聚合查询返回类型Long
- ”将一个unsigned long 型的IP转换为字符串类型的IP “ 解释
- 返回或输出类型为 unsigned 8-bit type(8U) 的函数积累!
- unsigned long long的问题
- CString的GetLength()函数返回为0问题解决
- 关于Hibernate select count(*)返回值为Long还是Integer?
- unsigned char 转换为 unsigned long方法
- C++ unsigned long 转化为 unsigned char*
- ICS TFTPClient 的相关操作。
- Memo 的当前行、当前列与当前字符
- Delphi XE2 新技术说明
- hdoj1257
- 一个最简单的Delphi2010的PNG异形窗口方法
- 返回值类型为unsigned long long的函数永远返回为0的问题解决
- ECSHOP模板制作中常见循环的操作方法
- 1.1 Linux shell 简介
- 开始了Android的系统开发旅程 主要是往rom方向走
- ecshop首页调用文章缩略图方法
- C++容器使用总结
- 完美解决Ecshop2.72与Jquery冲突的办法
- emule--电驴
- ecshop常见修改