为什么解除引用空指针是未定义的行为?

Raj*_*pal 22 c++ pointers undefined-behavior

根据ISO C++,取消引用空指针是未定义的行为.我的好奇心是,为什么?为什么标准决定声明它未定义的行为?这个决定背后的理由是什么?编译器依赖?似乎没有,因为根据C99标准,据我所知,它是明确定义的.机器依赖?有任何想法吗?

Mar*_*som 37

定义解除引用NULL指针的一致行为将要求编译器在大多数CPU体系结构上的每次取消引用之前检查NULL指针.对于一种专为速度而设计的语言而言,这是一种令人无法接受的现象.

它还只修复了一个较大问题的一小部分 - 有很多方法可以使无效指针超出NULL指针.

  • @Mehrdad:它如何假设`NULL`是特殊的?对于解除引用而言,与未初始化的指针或不再指向现有对象的指针相比,它并不特别. (2认同)

Jer*_*fin 23

主要原因是,当他们编写原始C标准时,有许多实现允许它,但给出了相互矛盾的结果.

在PDP-11上,地址0总是包含值0,因此解除引用空指针也会给出值0.相当多的人使用这些机器感觉因为它们是原始机器C已经写在/用来编程,这应该被认为是所有机器上C的规范行为(即使它最初是偶然发生的).

在其他一些机器上(Interdata浮现在脑海中,虽然我的内存很容易出错)地址0正常使用,因此它可能包含其他值.还有一些硬件,其中地址0实际上是一些内存映射硬件,因此读/写它做了特殊的事情 - 完全不等同于读/写普通内存.

难民营不会就应该发生什么达成一致,所以他们做出了不明确的行为.

编辑:我想我应该在编写C++标准时添加它,它的未定义行为已经在C中已经很好地建立了,并且(显然)没有人认为有充分的理由在这一点上产生冲突,所以他们保留了相同.

  • 值得注意的是,在C89发布之前,它没有对*any*行为提出任何要求,但许多C实现确实定义了很多事情的行为.如果某些C编译器为某些操作定义了一个行为,而某些行为没有定义,则保留行为未定义只会保留现状.直到最近,标准未能定义事物才被解释为表明没有合理的代码 - 甚至代码定位平台,这些平台定义了*之前的行为*是C标准 - 应该使用标准以外的任何东西. (2认同)

Mik*_*our 11

给定义行为的唯一方法是向每个指针取消引用和每个指针算术运算添加运行时检查.在某些情况下,这种开销是不可接受的,并且会使C++不适合它经常使用的高性能应用程序.

C++允许您创建自己的智能指针类型(或使用库提供的类型),其中包括安全性比性能更重要的情况下的检查.

根据C99标准的第6.5.3.2/4节,在C中取消引用空指针也是未定义的.

  • 这不是真的.定义的行为可以简单地是"只要不访问该值就可以取消引用空指针.如果访问结果左值的值,则行为未定义".这不需要任何检查. (4认同)

Alo*_*ave 8

从@Johannes绍布答案- litb,提出了一个有趣的理由,这似乎非常有说服力.


仅仅取消引用空指针的形式问题是确定结果左值表达式的标识是不可能的:取消引用指针所产生的每个这样的表达式必须在评估该表达式时明确地引用对象或函数.如果取消引用空指针,则没有此左值标识的对象或函数.这是标准用于禁止空引用的参数.

另一个增加混乱的问题是typeid运算符的语义很好地定义了这种痛苦的一部分.它说如果给出了一个左引用取消引用空指针的结果,结果就是抛出一个bad_typeid异常.尽管如此,这是一个有限的区域,其中存在对上述寻找身份的问题的例外(没有双关语).存在其他情况,其中对未定义的行为进行类似的异常(尽管不那么微妙并且在受影响的部分上有引用).

委员会讨论了通过定义一种没有对象或函数标识的左值来全局解决这个问题:所谓的空左值.然而,这个概念仍有问题,他们决定不采用它.


注意:
将此标记为社区维基,因为答案和信用应该转到原始海报.我只是在这里粘贴原始答案的相关部分.


Mat*_* M. 5

真正的问题是,你会期待什么样的行为?

根据定义,空指针是表示缺少对象的奇异值.取消引用指针的结果是获取对指向的对象的引用.

那么如何从一个指向虚空的指针中得到一个好的参考?

你不.因此未定义的行为.

  • 抛出异常?提出一个信号?叫`abort()`?有很多明智的东西可以*定义; 问题是,为什么不定义呢? (5认同)