为啥代码会通过空指针显式调用静态方法?
Posted
技术标签:
【中文标题】为啥代码会通过空指针显式调用静态方法?【英文标题】:Why would code explicitly call a static method via a null pointer?为什么代码会通过空指针显式调用静态方法? 【发布时间】:2014-11-01 09:02:32 【问题描述】:我在几个旧项目中看到过这样的代码:
class Class
static void Method()
;
((Class*)0)->Method();
此代码包含未定义的行为,因为它包括取消引用空指针(无论之后发生什么)。这真的没有意义 - 转换是为了将类型名称提供给编译器,而编写上面代码的人可能已经编写了这个:
Class::Method();
后者也可以。
为什么有人会编写以前的代码?这是过去美好时光的成语还是什么?
【问题讨论】:
我怀疑这种东西来自可以与常规或静态方法一起使用的宏。 我不确定调用本身是否严格执行任何“取消引用”。虽然这可能发生在函数本身。 这有点像人们在添加到语言之前编写的offsetof()
宏中的假解引用。
这显然是一件坏事——我最好的猜测是,最初的 Method
不是静态的(但没有访问任何实例数据)并且有人使用这个 hack 来调用它。后来有人意识到Method
需要是静态的并对其进行了更改,但并未修复调用它的所有位置。
空指针 variable 与 this 一起使用更为常见。例如:VC++ DevCon 1999,DonBox 吹捧,CComObject<YourClass>* pObj = NULL; HRESULT hr = pObj->CreateInstance(&pObj);
“你知道你能做到,对吧?”好吧,read this 并决定你住在围栏的哪一边。很清楚唐在哪里闲逛。
【参考方案1】:
静态成员函数于 1989 年添加到 C++ 中,位于 AT&T C++ 语言系统的Release 2.0(预标准化)。在此之前,static
关键字不能用于声明静态成员函数,因此代码作者使用了变通方法,主要是您观察到的间接空指针的变通方法。
在Selected Readings 随附的 AT&T C++ 语言系统 2.0 版的第 1-22 节中,Stroustrup 写道:
还观察到不可移植的代码,例如:
((X*)0)->f();
用于模拟静态成员函数。这个技巧是一个定时炸弹,因为迟早有人会创建一个
f()
,以这种方式使用virtual
,并且调用将严重失败,因为地址零处没有X
对象。即使f()
不是虚拟的,这样的调用在某些动态链接实现下也会失败。
您的代码是为在 Cfront 1.0 下编译而编写的,或者是由在向语言中添加静态成员函数时不知道的人编写的。
static
的成员函数的注解确实是一个谜,就像Cheers and hth。 - Alf 观察到; Cfront 1.0 会拒绝该代码:
error: member Method() cannot be static
所以它最初不可能存在。我认为 Potatoswatter 很可能是正确的; static
是后来添加的,用于记录和强制执行 Method
的静态方法属性,一旦可以保证 C++ 2.0 编译器可用,但调用代码不会被更新。要确认这一点,您需要采访原始程序员或至少检查源代码控制历史(如果存在)。
【讨论】:
为什么 Stroustrup 没有提到更严重的未定义行为问题?他与实施细节争论不休。 @usr 不言而喻,崩溃实际上是由于未定义的行为理论上。 @usr:Stroustrup 不能争论 1998 年之前的未定义行为,例如 1989 年之前的代码(此代码),因为那将毫无意义。那时,该语言只是由他的《C++ 编程语言》一书非正式地和部分定义的。 -1 一般不错的答案!但是,两次错误的结论“您的代码是在 C++ 1.x 下编译的,或者是由在向语言中添加静态成员函数时不知道的人编写的。”由于代码使用了static
关键字,因此这些可能性都不成立。如果没有 static
成员函数,该代码将无法在 C++ 版本中编译。而使用static
的程序员不可能不知道这一点。抱歉,我没有早点读到。
@Cheersandhth.-Alf 可能客户端(函数调用)代码更复杂,并且库(类定义)在引入后更新为static
。或者,它是两个程序员的产物,其中一个不合时宜。以上是关于为啥代码会通过空指针显式调用静态方法?的主要内容,如果未能解决你的问题,请参考以下文章
为啥可以从指向实例化基类对象的强制转换指针调用非静态派生类方法?
为啥在空引用上调用(静态)方法不会抛出 NullPointerException?