首页 > 编程语言 >C/C++杂记:NULL与0的区别、nullptr的来历

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

时间:2023-05-31 15:12:14浏览次数:41  
标签:常量 void nullptr C++ NULL pointer 指针

某些时候,我们需要将指针赋值为空指针,以防止野指针。   有人喜欢使用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标准文档   (2) nullptr提案文档:N2431:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf

标签:常量,void,nullptr,C++,NULL,pointer,指针
From: https://www.cnblogs.com/tomato-haha/p/17446179.html

相关文章

  • C/C++杂记:深入虚表结构
    1.虚表与“虚函数表”在“C/C++杂记:虚函数的实现的基本原理”一文中曾提到“虚函数表”的概念,只是为了便于理解,事实是:虚函数表并不真的独立存在,它只是虚表(virtualtable)中的一部分内容。例:从图中可已看出,虚表除了包含虚函数指针,还包含其它一些信息(如:RTTI信息、偏移值等)。顺便......
  • 多线程或监听器@Autowired注入null空指针
    //问题:在多线程中使用@Autowired注入IUserService时,userService使用时为null,获取不到bean//原因:newthread不在spring容器中,也就无法获得spring中的bean对象;@AutowiredprivateIUserServiceuserService;//解决:手动获取bean对象privateIUserServiceuserService=AppCo......
  • 关于C++字符串的一些函数
    其实印象里,c的char用法反倒比c++的string深一点,可能是因为我对string的运用太少了吧。 提到C++的string,就得先提一下首先提一下C的char类型,毕竟C++是根据C延展过来的,继承了C的特性,而且C本身是没有string这个东西的。 char是什么?一个关键字,用于声明一个变量是字符类型。好吧,......
  • C++ 运算符
     运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C++内置了丰富的运算符,并提供了以下类型的运算符:算术运算符关系运算符逻辑运算符位运算符赋值运算符杂项运算符本章将逐一介绍算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和其他运算符。ht......
  • proc c++ vs设置
    1、在pc文件上右键,项类型中选择自定生成工具,点击应用才能看见自定义生成工具2.命令行和输出中中配置,proc是oracle的执行程序在(client_1\BIN)目录下 ......
  • c/c++零基础坐牢第十七天
    c/c++从入门到入土(17)开始时间2023-05-30 21:31:54结束时间2023-05-31 13:29:07前言:第九章多态性从作业七作业八实验三和读书笔记及体会四个方面进行学习分享,课本知识参考于清华大学出版社郑莉老师的《C++语言程序设计》第五版,以下为自制思维导图: 第九章 多态性1面向......
  • C/C++数据结构课程设计[2023-05-31]
    C/C++数据结构课程设计[2023-05-31]数据结构课程设计实验(训)指导书所在学院:计算机科学与工程学院编写说明一.实验总体目标《数据结构》是一门实践性较强的课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。本实验的目标是,学生能正确理解和熟练掌握常用数据结构和算......
  • C++四种强制类型详解
    向上转型(上行转换)派生类对象转换为基类对象(包括指针和对象),直接转换由编译器完成,是绝对安全的内存里面:基类对象相当于只是换了个地址,换成了派生类中存储基类成员的内存地址,但是派生类对象中有的,基类没有的变量仍然存在内存中(保留了再次从基类转换成派生类的可能性)向下转型(下行......
  • C/C++杂记:运行时类型识别(RTTI)与动态类型转换原理
    运行时类型识别(RTTI)的引入有三个作用:配合typeid操作符的实现;实现异常处理中catch的匹配过程;实现动态类型转换dynamic_cast。1.typeid操作符的实现1.1.静态类型的情形C++中支持使用typeid关键字获取对象类型信息,它的返回值类型是conststd::type_info&,例:#include<type......
  • C/C++杂记:虚函数的实现的基本原理
    1.概述简单地说,每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应的函数指针。例:其中:B的虚函数表中存放着B::foo和B::bar两个函数指针。D的虚函数表中存放的既有继承自B的虚函数B::foo,又有重写(override)了基......