&(((AClass*)0)->aProperty) 这样的表达式会报错吗?

#include <iostream>

using namespace std;

class TestProperty{

public:
int mp1;
int mp2;
int mp3;
};

void testProperty(){
cout<<&(((TestProperty*)0)->mp1)<<endl;
cout<<&(((TestProperty*)0)->mp2)<<endl;
cout<<&(((TestProperty*)0)->mp3)<<endl;
cout<<((TestProperty*)0)->mp1<<endl;

}

以上几个表达式能正常输出吗,如果能,输出的又是什么呢?


这是前三个表达式的输出,最后一个会造成程序的崩溃

编译器看到&(((TestProperty*)0)->mp1)这个表达式的时候,知道这句是为了获取mp1的地址,而此时,地址是知道的,所以就直接打印出来了,下面对应的汇编代码

73:       cout<<&(((TestProperty*)0)->mp1);
00401808   push        0
0040180A   mov         ecx,offset std::cout (0047eea0)
0040180F   call        @ILT+75(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401050)
74:       cout<<&(((TestProperty*)0)->mp2);
00401814   push        4
00401816   mov         ecx,offset std::cout (0047eea0)
0040181B   call        @ILT+75(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401050)
75:       cout<<&(((TestProperty*)0)->mp3);
00401820   push        8
00401822   mov         ecx,offset std::cout (0047eea0)
00401827   call        @ILT+75(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401050)

其中的0 4 8 就是编译器已经算好的地址,准确的说,是偏移地址,相对于类首地址的偏移地址

那为何 最后一句会崩呢,下面是对应的汇编代码

76:       cout<<((TestProperty*)0)->mp1;
0040182C   mov         eax,[00000000]
00401831   push        eax
00401832   mov         ecx,offset std::cout (0047eea0)
00401837   call        @ILT+275(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401118)

此时编译器认为是想取得mp1的内容,而此时mp1还没分配好内存空间,于是在调用mov eax,[00000000]的时候,发生访问异常了。

把代码修改一下

class TestProperty{
public:
int mp1;
int mp2;
int mp3;
public:
void func1(){printf("hello TestProperty");}
};

void testProperty(){
(((TestProperty*)0)->func1());
printf("%d",((TestProperty*)0)->func1);//vc6可以这么写,但在vs2013中这么会报错
}

会正常输出吗?



为何第一句不会崩?因为方法早在类还没初始化的时候,已经在代码区生成了,它与类的构造没有关系,看对应的汇编代码

76:       (((TestProperty*)0)->func1());
004013E8   xor         ecx,ecx
004013EA   call        @ILT+0(TestProperty::func1) (00401005)
77:       printf("%d\n",((TestProperty*)0)->func1);
004013EF   push        offset @ILT+0(TestProperty::func1) (00401005)
004013F4   push        offset string "%d\n" (0043401c)
004013F9   call        printf (00409260)

由于在调用func1的时候,应该在ecx传入调用者的地址,而这里为0,所以直接xor ecx,ecx对其清空了,然后正常的调用了func1,但如果func1中使用了this指针,那就

肯定非法了,因为此时this指针为null

对于printf("%d\n",((TestProperty*)0)->func1);就是打印函数的地址了,这个在vc6中可以正常运行,但在vs2013会报调用函数需要传参的错误,所以就用内联汇编来

代替了,如下:

char* myword = "%d\n";
__asm{
mov eax, offset TestProperty::func1
push eax
push dword ptr[myword]
call printf
add esp,8
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值