C++ 为什么通过空指针调用方法;工作“;在C++;?

C++ 为什么通过空指针调用方法;工作“;在C++;?,c++,C++,可能重复: #包括 使用名称空间std; 课堂测试 { int i; 公众: test():i(0){cout调用该方法不需要指针。指针的类型已知,因此该方法的代码已知。该方法不使用this,因此它可以很好地运行代码。这是未定义的行为,但更有效的方法是不检查指针是否为NULL,因此它会运行。这是无效的,行为是未定义的实际结果取决于您的编译器。首先,它无效,因为它调用了未定义的行为。您真的在问编译器为什么允许它,答案是因为这是根本不会在实际应用程序中出现的愚蠢代码,所以为什么要麻烦呢?真正的问题

可能重复:

#包括
使用名称空间std;
课堂测试
{
int i;
公众:

test():i(0){cout调用该方法不需要指针。指针的类型已知,因此该方法的代码已知。该方法不使用
this
,因此它可以很好地运行代码。这是未定义的行为,但更有效的方法是不检查指针是否为NULL,因此它会运行。

这是无效的,行为是未定义的实际结果取决于您的编译器。

首先,它无效,因为它调用了未定义的行为。您真的在问编译器为什么允许它,答案是因为这是根本不会在实际应用程序中出现的愚蠢代码,所以为什么要麻烦呢?真正的问题是指针在运行时i无效n一种静态代码分析无法预料的方式


编译器并不是用来牵手的,它是用来根据标准编译代码的。如果它提供了有用的警告,那就太好了,但在语法或语义上没有什么不合法的地方,你只是在编写导致未定义行为的代码。

如果你查看程序集(至少有一个编译器),您可以看到它运行的原因(尽管它是许多人指出的未定义的行为)

test *ptr = NULL;
ptr->show();
生成此程序集(在我刚刚尝试的一个编译器中):


它在堆栈上推送NULL(0)并调用该方法,因为该方法的地址独立于实际的对象实例。

取消对NULL指针的引用是UB.Add
i=1;
inside
show()
并试着运行它。chris,UB意味着编译器实现吗?我使用的是g++4.6.3。Jesse很好,当然是seg fault,这是毫无疑问的。我想知道编译器是否会为不需要它的成员函数生成没有它的代码。@bbc:UB意味着“未定义的行为”,这与“已定义的实现”不同.Implementation defined意味着至少定义了行为,尽管编译器之间的定义可能有所不同。此外,“当然,seg fault,这是毫无疑问的。”-事实上,有很多疑问,因为行为是未定义的。如果它确实会导致segfault,那么它将是完全定义好的,而事实并非如此。任何事情都可能发生,尽管在实践中很可能发生segfault(您希望如此)。您的代码在大多数编译器下都是有效的[这里没有在GCC和MSVC上崩溃]。幸运的是,您的show()方法限定为纯静态。您没有取消对指针的引用!对指向非多态类的指针的函数调用不会取消对指针的引用。它只调用具有堆栈帧的方法的地址,在堆栈帧中此指针为零。如果您的代码只使用全局变量,并且从不触及
指针-或“否”n-静态数据成员-您很好。触摸静态数据成员也很好。更好的是,只需将您的方法标记为静态并忘记指针!(如何)虚拟方法会影响他观察到的行为吗?我预计虚拟方法调用会失败,因为它需要在vtable中查找该方法,它会在指针的另一端找到该方法,但指针为NULL.seg fault for virtual with g++,不确定这是否也依赖于实现。编译器会生成vptr和vtblr吗hout类的对象?猜测不是出于效率原因?经典的非虚拟方法通过asm调用直接调用。然后堆栈框架将
this
指针归零。但是,虚拟方法很可能会出错,因为指针必须被取消引用。嗯,这是有效的。\u thiscall函数不访问
this
点er只是一个静态函数。只需添加“static”-这是您在定义为静态的代码中所能做的最好的:)并强制函数使用_cdecl,因此不需要此指针要求。请注意,添加virtual将使准备工作更加复杂,需要取消引用指针,然后会出错。
test *ptr = NULL;
ptr->show();
00000004: C7 45 FC 00 00 00  mov         dword ptr [ebp-4],0
          00
0000000B: 8B 4D FC           mov         ecx,dword ptr [ebp-4]
0000000E: E8 00 00 00 00     call        ?show@test@@QAEXXZ