• C/C++杂记:NULL与0的区别、nullptr的来历


    某些时候,我们需要将指针赋值为空指针,以防止野指针。
     
    有人喜欢使用NULL作为空指针常量使用,例如:int* p = NULL;。
    也有人直接使用0值作为空指针常量,例如:int* p = 0;。
     
    前者可能觉得:NULL作为空指针常量,名字很形象,可读性较强。
    后者可能觉得:NULL并不是C/C++语言的关键字,而是一个在标准库头文件<stddef.h>中定义的宏,因此要使用NULL,可能需要直接或简介地包含<stddef.h>头文件,比较麻烦。
     
    问题一:NULL与常数0值有何区别?
     
    要弄清楚这个问题,我们采用问与答的形式来描述。
     
    问:NULL到底是什么?
     
    答:NULL是一个宏。
     
    问:它的值是多少?
     
    答:C/C++标准规定:它的值是一个空指针常量(null pointer constant),由实现定义。#1,#2
     
    问:什么样的值才能称之为空指针常量?
     
    答:C语言中常数0和(void*)0都是空指针常量;C++中(暂且忽略C++11)常数0是,而(void*)0 不是。#3,#4
     
    问:NULL宏是在哪里定义的?
     
    答:通常是在C标准库的<stddef.h>头文件中,不过别的头文件中可能也有定义。
     
    问:一般编译器的<stddef.h>头文件中NULL宏是如何定义的?
     
    答:以gcc或clang编译器为例,NULL的定义大致如下(稍有简化):
    #if defined(__cplusplus)
    # define NULL 0    // C++中使用0作为NULL的值
    #else
    # define NULL ((void *)0)    // C中使用((void *)0)作为NULL的值
    #endif

     

    问:为什么C中(void*)0是空指针常量,而C++中不是?
     
    答:因为C语言中任何类型的指针都可以(隐式地)转换为void*型,反过来也行,而C++中void*型不能隐式地转换为别的类型指针(例如:int*p = (void*)0;使用C++编译器编译会报错)。#5,#6
     
    问:既然C/C++标准中,常数0都可作为空指针常量,为什么不统一使用0?
     
    答:个人觉得由于(void*)0更能体现指针的意义,而常数0更多的时候是用作整数。因此,C语言中NULL定义选择了(void*)0。(仅供参考)
     
    问题二:C++11中为什么要引入nullptr?
     
    考虑着这样一个函数重载的情形:
    #include <stddef.h>
    void foo(int) {}     // #1
    void foo(char*) {}   // #2
    int main() {
        foo(NULL); // 调用#1还是#2?
    }
    从字面上来讲,NULL是个空指针常量,我们可能会觉得:既然是个指针,那么应该调用#2。但事实上调用的却是#1,因为C++中NULL扩展为常数0,它是int型。
     
    根本原因就是:常数0既是整数常量,也是空指针常量。
     
    为了解决这种二义性,C++11标准引入了关键字nullptr,它作为一种空指针常量。#7例如:
     
    void foo(int) {}     // #1
    void foo(char*) {}   // #2
    int main() {
        foo(nullptr); // 它会毫无异议地调用#2
    }
    附注:
     
    [#1] C99: 7.17-p3:
        The macros are
            NULL
        which expands to an implementation-defined null pointer constant; and ...
     
    [#2] C++03: 18.1-p4:
        The macro NULL is an implementation-defined C + + null pointer constant in this International Standard(4.10).
     
    [#3] C99: 6.3.2.3-p3:
        An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
     
    [#4] C++03: 4.10-p1:
        A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.
     
    [#5] C99: 6.3.2.3-p1:
        A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
     
    [#6] C++03: 4.10-p2:
        An rvalue of type “pointer to cv T,” where T is an object type, can be converted to an rvalue of type “pointer to cv void.”
     
    [#7] C++11: 4.10-p1:
        A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t.
     
    参考:
     
    (1) C99/C++03/C++11标准文档
     
  • 相关阅读:
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第4章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第3章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第1,2章 读书笔记(待更新)
    Tkinter的Message组件
    Git 实操/配置/实践
    mysq5.7.32-win安装步骤
    行为型模式之模板方法
    结构型模式之组合模式
    结构型模式之享元模式
    结构型模式之外观模式
  • 原文地址:https://www.cnblogs.com/malecrab/p/5569707.html
Copyright © 2020-2023  润新知