事件起因
最近在做一个32位程序编译成64位的工作,遇到一个很奇葩的问题,程序在32位下运行非常正常,可编译64位以后总是莫名崩溃,崩溃的的报错是这样的。
经过分析发现原来是以前的代码用DWORD来存储指针导致的地址越界错误。
现场模拟
先看一段代码
#include <stdio.h>
#include <windows.h>void func_a(){printf("func_a output");
}typedef void funca();int main()
{DWORD ptr_func_a = (DWORD)&func_a;printf("%p\n",&func_a);funca* p_func=(funca*)ptr_func_a;printf("%p\n", p_func);p_func();return 0;
}
这段代码在32位下能正常运行,改成64位就会出现越界异常
32位运行截图
原因分析
DWORD不论在32位还是64位下都是4字节32位长,因此在64位下保存函数地址的时候就会发生截断,只保存了前32位,后32地址丢失了,进而访问函数地址的时候就会出现一个不存在的地址。
从打印的地址可以看出函数地址的高位已经丢失了
如何避免这种问题发生
不要用DWORD存储指针,可以改用DWORD_PTR,DWORD_PTR定义的时候针对64位和32位分别做了不同的定义
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
//...省略一万字#if defined(_WIN64)typedef __int64 INT_PTR, *PINT_PTR;typedef unsigned __int64 UINT_PTR, *PUINT_PTR;typedef __int64 LONG_PTR, *PLONG_PTR;typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;#define __int3264 __int64#elsetypedef _W64 int INT_PTR, *PINT_PTR;typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;typedef _W64 long LONG_PTR, *PLONG_PTR;typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;#define __int3264 __int32#endif
修改后的运行结果