原文: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. jq实现 元素显示后 点击页面的任何位置除元素本身外 隐藏元素

    $(".share-weixin").on("click",function(e){ var $wx=$(".weixin-share"), ...

  2. angularJs购物金额实例操作

    <!DOCTYPE HTML> <html ng-app> <head> <meta http-equiv="Content-Type" ...

  3. ApplicationEventPublisher笔记

    ApplicationEventPublisher是ApplicationContext的父接口之一.这接口的作用是:Interface that encapsulates event publica ...

  4. 【小M的作物】

    这是一道我好像没写过的最小割 这道题如果没有那\(m\)条限制,我们完全可以贪心来做 但是硬要用网络流怎么办 可以转化为最小割模型 我们将源点\(S\)表示为耕地\(A\),汇点\(T\)表示为耕地\ ...

  5. HttpURLConnection与HttpClient学习

    转载HttpURLConnection与HttpClient浅析 一.HttpURLConnection的使用 import org.slf4j.Logger; import org.slf4j.Lo ...

  6. Git删除commit提交的log记录

    基于 GitFlow 工作流,可能某个提交(commit)导致了 bug,或者有多个提交需要返工,此时你就会用到删除提交. 接下来的内容都基于下面这张 git log 提交记录图来写.   git l ...

  7. windows ionic bash: command not found

    安装好了node.js和npm后,执行npm install -g cordova ionic后,成功安装,但是执行ionic命令后,返回 command not found. 配置好了环境变量后,仍 ...

  8. Linux Notes | Linux常用命令行笔记

    [ show all running processes ] (1) ps -aux | less 'ps' means: Process Status The -a option tells ps ...

  9. CSS动画总结效果

       CSS3添加了几个动画效果的属性,通过设置这些属性,可以做出一些简单的动画效果而不需要再去借助JavaScript.CSS3动画的属性主要分为三类:transform.transition以及a ...

  10. 轻量ORM-SqlRepoEx (十五)最佳实践之数据映射(Map)

    简介:SqlRepoEx是 .Net平台下兼容.NET Standard 2.0人一个轻型的ORM.解决了Lambda转Sql语句这一难题,SqlRepoEx使用的是Lambda表达式,所以,对c#程 ...