项目中遇到一个奇怪的函数返回值的问题
a.h
typedef char mybool;
#define myfalse 0
#define mytrue 1
a.c
#include "a.h"
//原函数比这复杂,需要做很多逻辑判断
mybool f()
{
return myfalse;
}
#include "a.h"
int main()
{
if (f())
{
return 1;
}
return 0;
}
编译后调试发现始终执行return 1,与预期不符,百思不得其解
为确定f()返回值,修改main函数
int main()
{
mybool b;
if (b = f())
{
return 1;
}
return 0;
}
调试发现b的值为0,在未修改函数f以及测试环境的情况下执行出了2种结果!!!
=======================================================================
怀疑是编译器优化行为导致该问题出现,于是开始跟踪汇编代码
4: mybool f()
5: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,40h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-40h]
0040102C mov ecx,10h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
6: return myfalse;
00401038 xor al,al
7: }
返回值使用的是xor al,al,只对eax的低位进行了屏蔽为0,查看寄存器eax的值,高位不为0
直接判断f()返回值的汇编代码
10: if (f())
00401068 call @ILT+0(_f) (00401005)
0040106D test eax,eax
0040106F je main+28h (00401078)
赋值后判断f()返回值的汇编代码
10: if (b=f())
00401068 call @ILT+0(_f) (00401005)
0040106D mov byte ptr [ebp-4],al
00401070 movsx eax,byte ptr [ebp-4]
00401074 test eax,eax
00401076 je main+2Fh (0040107f)
在赋值后,因使用movsz指令读取变量到eax进行test,对高位进行符号扩展,使得与低位一致
不赋值时,编译器认为f()返回的是个int值,直接对返回值的寄存器eax进行判断,导致发生了问题
可以看到编译器警告
'f' undefined; assuming extern returning int
=================================================================================
找到了问题根源,解决方法,将f()的声明加入到头文件
typedef char mybool;
#define myfalse 0
#define mytrue 1
mybool f(void);
=================================================================================
反思:
编译时编译器并不会检查函数实现,链接时才查找函数符号,可能导致不一致的执行结果,处理编译器的警告信息非常重要