64位地址强转和解引用注意长度


在看C++对象模型相关的帖子,最常见的是直接拿对象的地址去取虚表地址,代码如下:

Base b;
printf("%p\n", (int*)*(int*)*(int*)(&b));

但是,这里的代码是在32位下的,如果是x64位就直接宕了

长度

原因是x64位的地址是64位的,而x86下面是32位的。

// x86下面的地址
0034116D
003412EE

// x64下面打印的地址
00007FF664371447
00007FF66437108C

出问题的地方主要是强转之后解引用发生的,在x64下面int指针还是64位的,强转没有问题。但是,如果(int*)之后就出问题了,拿到一个int类型的整数,只有32位。而后面又去把它转成int*的64位地址,高位用0xFFFFFFFF补全,结果就不对了。

0x00007FF6BB966841 处(位于 diffrent_address_study.exe 中)引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFBB96AD30 时发生访问冲突。

开始以为把int换成long就行了,结果死翘翘,long也是4位。这个估计得看系统了,我得win10下面,x64下面的长度如下

sizeof(int) = 4
sizeof(long) = 4
sizeof(int*) = 8
sizeof(long*) = 8
sizeof(intptr_t) = 8

解决

使用intptr_t代替

看定义

// Definitions of common types
#ifdef _WIN64
    typedef unsigned __int64 size_t;
    typedef __int64 ptrdiff_t;
    typedef __int64 intptr_t;
#else
    typedef unsigned int size_t;
    typedef int ptrdiff_t;
    typedef int intptr_t;
#endif

所以,这也提醒我自己,以后写代码地址转成int这样的操作很危险。用库里面有的类型,比如这里intptr_t。

跳过解引用运算符

还看到一些网友[1]的写法,我觉得这个比较好,跳过了解引用运算符的操作,也就不会出现问题了。而且对于虚表也比较清晰

Base b;
long** pVtab = (long**)&b;

参考

[1]C++对象在64位机器上的内存布局

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值