原文: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标准文档
 

【转载】C/C++杂记:NULL与0的区别、nullptr的来历的更多相关文章

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

    某些时候,我们需要将指针赋值为空指针,以防止野指针.   有人喜欢使用NULL作为空指针常量使用,例如:int* p = NULL;. 也有人直接使用0值作为空指针常量,例如:int* p = 0;. ...

  2. c语言NULL和0区别及NULL详解

      先看下面一段代码输出什么: #include<stdo.h> int main() { int *p=NULL; printf("%s",p); } 输出<n ...

  3. Pointer's NULL And 0

    问题起源 在使用Qt框架的时候, 经常发现一些构造函数 *parent = 0 这样的代码. 时间长了, 就觉的疑惑了. 一个指针不是等于NULL吗? 这样写, 行得通吗? 自己测试一下就可以了. 测 ...

  4. 《征服 C 指针》摘录1:什么是空指针?区分 NULL、0 和 '\0'

    一.什么是空指针? 空指针 是一个特殊的指针值. 空指针 是指可以确保没有向任何一个对象的指针.通常使用宏定义 NULL 来表示空指针常量值. 空指针 确保它和任何非空指针进行比较都不会相等,因此经常 ...

  5. 字符数组和string判断是否为空行 NULL和0 namespace变量需要自己进行初始化

    string 可以这样判断空行input !="" 字符数组可以通过判断第一个元素是否为空字符'\0',是的话为空行arrar[0]=='\0':或者用长度strlen(char ...

  6. 字符串怎么换行 || 字符串中使用单引号时应该怎么写 || 保留两位小数 || 数字0在if中的意思是false || 什么情况下会会报undefined || null和undefined的区别 ||

    换行的字符串 "This string\nhas two lines" 字符串中使用单引号时应该怎么写 'You\'re right, it can\'t be a quote' ...

  7. php中0," ",null和false的区别

    php中很多还不懂php中0,"",null和false之间的区别,这些区别有时会影响到数据判断的正确性和安全性,给程序的测试运行造成很多麻烦.先看一个例子: <? $str ...

  8. [转载]触发ASSERT(afxCurrentResourceHandle != NULL)错误的原因

    触发ASSERT(afxCurrentResourceHandle != NULL)错误的原因 Debug Assert error afxwin1.inl line:22 翻译参考 http://w ...

  9. MySQL 中NULL和空值的区别 (转载 http://blog.sina.com.cn/s/blog_3f2a82610102v4dn.html)

    平时我们在使用MySQL的时候,对于MySQL中的NULL值和空值区别不能很好的理解.注意到NULL值是未知的,且占用空间,不走索引,DBA建议建表的时候最好设置字段是NOT NULL 来避免这种低效 ...

随机推荐

  1. SVG中的元素属性

    SVG attributes by category Animation event attributes onbegin, onend, onload, onrepeat Animation att ...

  2. Charles使用笔记

    Charles本身其实是一款十分强大且易用的代理软件,最近用的比较多,大致整理了一下自己用到的一些东西.   Charles的主要作用 1.查看网络请求,手动分析数据 2.代理接口,模拟数据      ...

  3. 劳动节前得空半天-总结一下最近使用的LINUX命令

    一.搜索文件 1.locate xxx.log   全盘搜索xxx.log文件 2.which java       查找命令 3.ll  xxx.log         在目录下查找文件 二.搜索内 ...

  4. Spring Cloud(四):服务容错保护 Hystrix【Finchley 版】

    Spring Cloud(四):服务容错保护 Hystrix[Finchley 版]  发表于 2018-04-15 |  更新于 2018-05-07 |  分布式系统中经常会出现某个基础服务不可用 ...

  5. CentOS 7.0 防火墙操作

    CentOS 7.0默认使用的是firewall作为防火墙,之前版本是使用iptables.所以在CentOS 7执行下面命令是无法查看防火墙状态的. [root@localhost ~]# serv ...

  6. Oracle 12.2 设置LOCAL_TEMP_TABLESPACE

    12.2 设置LOCAL_TEMP_TABLESPACE SQL>  select username,DEFAULT_TABLESPACE,TEMPORARY_TABLESPACE,LOCAL_ ...

  7. iOS:多媒体(18-01-25更)

    1.音频 2.视频 1. 2.AVPlayer 1.音频 2.视频 1. 2.AVPlayer 0).写在前面 AVPlayer 主要包含 AVPlayer.AVPlayerItem.AVPlayer ...

  8. 初试mininet(可选PyCharm)

    目录 0x00 Mininet 0x01 Important classes, methods, functions 0x02 Sample 0x04 run in shell 0x05 Output ...

  9. kafka搭建到配置borker集群(项目开发-区块链)

    (以下分享了搭建kafka需要使用到的命令,差不多齐了,这里没有提到kafka-manager ,同学可以在网上自行查找) 最近公司的项目比较紧,先说下使用kafka的用处: 要替代原来 撮合引擎发数 ...

  10. C# 依据鼠标坐标取网页内成员坐标.ie

    C# 根据鼠标坐标取网页内成员坐标.ie 有时候你需要后台获取ie浏览器 鼠标所在位置的元素坐标,然而你使用屏幕坐标是不可行的 所以我们需要把坐标转换成浏览器内坐标 然后再通过elementFromP ...