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

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

为解引用NULL指针定义一致的行为将要求编译器在大多数CPU体系结构上的每个解引用之前检查NULL指针。 对于速度devise的语言而言,这是一个令人无法接受的问题。

它也只修复了一个较大问题的一小部分 – 有很多方法在NULL指针之外有一个无效的指针。

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

在PDP-11上,发生地址0总是包含值0,所以解除引用空指针也赋值0.不less人使用这些机器感觉到,因为它们是原来的机器C写在/用于编程,这应该被认为是所有机器上的C的规范行为(尽pipe它最初是偶然发生的)。

在其他一些机器上(Interdata想到了,虽然我的内存很容易出错),地址0被正常使用,所以它可以包含其他的值。 也有一些地址0实际上是一些内存映射硬件的硬件,所以读/写它做了特别的事情 – 完全不等同于读/写普通内存。

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

编辑:我想我应该补充一点,在编写C ++标准的时候,它的未定义行为已经在C语言中很好地build立起来了,并且(显然)没有人认为有足够的理由在这一点上产生冲突,所以他们相同。

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

C ++允许您创build自己的智能指针types(或使用库提供的types),在安全性比性能更重要的情况下,可以包含这种检查。

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

这个答案来自@Johannes Schaub – litb,提出了一个有趣的理由,这似乎很有说服力。


仅仅解除引用空指针的正式问题是,确定得到的左值expression式的身份是不可能的:每一个这样的由解引用指针引起的expression式都必须在评估expression式时明确地引用对象或函数。 如果您取消引用空指针,则不具有此左值标识的对象或函数。 这是标准用来禁止空引用的参数。

另外一个令人困惑的问题是, typeid操作符的语义成为定义好的痛苦的一部分。 它说,如果它被赋予一个左值引起的空值指针,结果是抛出一个bad_typeidexception。 虽然这是一个有限的领域,存在上述寻找身份的问题的例外(无双关)。 其他情况下也存在类似的未定义行为的例外情况(虽然less得多,并且对受影响的部分有参考)。

委员会通过定义一种不具有对象或function身份的左值来讨论全局解决这个问题:所谓的空左值。 但是,这个概念仍然存在问题,他们决定不采纳


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

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

根据定义,空指针是表示没有对象的奇异值。 解引用指针的结果是获得对所指向的对象的引用。

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

你不。 因此这个未定义的行为

我怀疑这是因为如果行为是定义良好的,编译器必须在指针被解引用的地方插入代码。 如果定义了实现,那么一个可能的行为仍然是一个严重的崩溃。 如果没有指定,那么某些系统的编译器会有额外的不必要的负担,或者可能会生成导致硬崩溃的代码。

因此,为了避免编译器可能的额外负担,他们留下了未定义的行为。

有时候你需要一个无效的指针 (也见Windows上的MmBadPointer )来表示“无”。

如果一切都是有效的,那么这是不可能的。 所以他们使NULL无效,并且不允许你解除引用。

尽pipe在C / C ++中取消引用NULL指针确实导致了从语言的angular度来看未定义的行为,但是在具有相应地址的存储器的目标的编译器中定义了这样的操作。 在这种情况下,这种操作的结果是简单地读取地址0处的存储器。

而且,只要不绑定引用的值,许多编译器将允许您取消引用NULL指针。 这样做是为了提供兼容性,但不符合广泛的代码,如

 #define offsetof(st, m) ((size_t)(&((st *)0)->m)) 

甚至有一个讨论 ,使这种行为的一部分标准。

根据原来的C标准, NULL可以是任何值不一定是零

语言定义指出,对于每种指针types,都有一个特殊的值 – “空指针” – 它可以与所有其他指针值区分开来,并且“保证比较不等于指向任何对象或函数的指针”。 也就是说,一个空指针肯定无处指向; 它不是任何对象或函数的地址

每个指针types都有一个空指针,不同types的空指针的内部值可能不同。

(来自http://c-faq.com/null/null1.html

这是一个简单的testing和示例:

  1. 分配一个指针:

    int *指针;

创build时指针的值是多less?
指针指向什么?
当我在当前状态下解除这一点时会发生什么?

  1. 标记链表的末尾。 在链表中,一个节点指向另一个节点,除了最后一个。
    最后一个节点中指针的值是多less?
    当你抛弃最后一个节点的“下一个”字段时会发生什么?

需要是一个指示指针的值不是指向任何东西或者它处于无效状态。 这是空指针概念进入的地方。 链表可以使用NULL指针来指示列表的结尾。

因为你不能创build一个空引用。 C ++不允许它。 因此你不能解引用空指针。

主要是没有定义,因为没有合理的方法来处理它。

你实际上可以解引用一个空指针。 有人在这里: http : //www.codeproject.com/KB/system/soviet_kernel_hack.aspx