C的NULL

在C语言中,我们使用NULL表示空指针,也就是我们可以写如下代码:

int *i = NULL;
foo_t *f = NULL;

实际上在C语言中,NULL通常被定义为如下:

#define NULL ((void *)0)

也就是说NULL实际上是一个void *的指针,然后吧void *指针赋值给int *和foo_t *的指针的时候,隐式转换成相应的类型。而如果换做一个C++编译器来编译的话是要出错的,因为C++是强类型的,void *是不能隐式转换成其他指针类型的,所以通常情况下,编译器提供的头文件会这样定义NULL:

#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif

C++的0

因为C++中不能将void *类型的指针隐式转换成其他指针类型,而又为了解决空指针的问题,所以C++中引入0来表示空指针,这样就有了类似上面的代码来定义NULL。实际上C++的书都会推荐说C++中更习惯使用0来表示空指针而不是NULL,尽管NULL在C++编译器下就是0。为什么C++的书都推荐使用0而不是NULL来表示空指针呢?我们看一个例子:

在foo.h文件中声明了一个函数:

void bar(sometype1 a, sometype2 *b);

这个函数在a.cpp、b.cpp中调用了,分别是:

a.cpp:


bar(a, b);

b.cpp:


bar(a, 0);

好的,这些代码都是正常完美的编译运行。但是突然在某个时候我们功能扩展,需要对bar函数进行扩展,我们使用了重载,现在foo.h的声明如下:

void bar(sometype1 a, sometype2 *b);
void bar(sometype1 a, int i);

这个时候危险了,a.cpp和b.cpp中的调用代码这个时候就不能按照期望的运行了。但是我们很快就会发现b.cpp中的0是整数,也就是在overload resolution的时候,我们知道它调用的是void bar(sometype1 a, int i)这个重载函数,于是我们可以做出如下修改让代码按照期望运行:

bar(a, static_cast<sometype2 *>(0));

我知道,如果我们一开始就有bar的这两个重载函数的话,我们会在一开始就想办法避免这个问题(不使用重载)或者我们写出正确的调用代码,然而后面的这个重载函数或许是我们几个月或者很长一段时间后加上的话,那我们出错的可能性就会加大了不少。貌似我们现在说道的这些跟C++通常使用0来表示空指针没什么关系,好吧,假设我们的调用代码是这样的:

foo.h

void bar(sometype1 a, sometype2 *b);

a.cpp


bar(a, b);

b.cpp


bar(a, NULL);

当bar的重载函数在后面加上来了之后,我们会发现出错了,但是出错的时候,我们找到b.cpp中的调用代码也很快可能忽略过去了,因为我们用的是NULL空指针啊,应该是调用的void bar(sometype1 a, sometype2 *b)这个重载函数啊。实际上NULL在C++中就是0,写NULL这个反而会让你没那么警觉,因为NULL不够“明显”,而这里如果是使用0来表示空指针,那就会够“明显”,因为0是空指针,它更是一个整形常量。

在C++中,使用0来做为空指针会比使用NULL来做空指针会让你更加警觉。

C++ 11的nullptr

虽然上面我们说明了0比NULL可以让我们更加警觉,但是我们并没有避免这个问题。这个时候C++ 11的nullptr就很好的解决了这个问题,我们在C++ 11中使用nullptr来表示空指针,这样最早的代码是这样的,

foo.h

void bar(sometype1 a, sometype2 *b);

a.cpp


bar(a, b);

b.cpp


bar(a, nullptr);

在我们后来把bar的重载加上了之后,代码是这样:

foo.h

void bar(sometype1 a, sometype2 *b);
void bar(sometype1 a, int i);

a.cpp


bar(a, b);

b.cpp


bar(a, nullptr);

这时候,我们的代码还是能够如预期的一样正确运行。

在没有C++ 11的nullptr的时候,我们怎么解决避免这个问题呢?我们可以自己实现一个(《Imperfect C++》上面有一个实现):

const
class nullptr_t
{
public:
    template<class T>
    inline operator T*() const
        { return 0; }

template<class C, class T>
    inline operator T C::*() const
        { return 0; }
 
private:
    void operator&() const;
} nullptr = {};

虽然这个东西被大家讨论过很多次了,但是我觉得还是有必要再讨论一下,毕竟在C++ 11还没有普及之前,我们还是应该知道怎么去避免问题,怎么很快的找到问题。

c++11 NULL、0、nullptr的更多相关文章

  1. Javascript 中的false、0、null、undefined和空字符串对象

    在Javascript中,我们经常会接触到题目中提到的这5个比较特别的对象——false.0.空字符串.null和undefined.这几个对象很容易用错,因此在使用时必须得小心. 类型检测 我们下来 ...

  2. php中NULL、false、0、" "有何区别?

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

  3. empty和is_null以及isset函数在0、”0”、‘空串’、NULL、false、array()的计算值

    1empty:只要是非空或者非零的值都返回false,换句话说‘’.‘0’.0.null.false都返回true: 2is_null: 当参数满足下面三种情况时,is_null()将返回TRUE,其 ...

  4. 史上最明白的 NULL、0、nullptr 区别分析(老师讲N篇都没讲明白的东东),今天终于明白了,如果和我一样以前不明白的可以好好的看看...

    C的NULL 在C语言中,我们使用NULL表示空指针,也就是我们可以写如下代码: int *i = NULL; foo_t *f = NULL; 实际上在C语言中,NULL通常被定义为如下: #def ...

  5. NULL、0、nullptr

    C的NULL 在C语言中,我们使用NULL表示空指针,也就是我们可以写如下代码: int *i = NULL;foo_t *f = NULL; 实际上在C语言中,NULL通常被定义为如下: #defi ...

  6. NULL、0、nullptr的区别

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

  7. Javascript中那些你不知道的事之-- false、0、null、undefined和空字符串

    话不多说直接进入主题:(如果有写的不对的地方欢迎指正) 我们先来看看他们的类型分别是什么: typeof类型检测结果 结论:false是布尔类型对象,0是数字类型对象,null是object对象,un ...

  8. oracle基础:怎样把查询的null转换为0、打印、定义变量

    https://blog.csdn.net/xuxile/article/details/49943665 oracle怎样把查询的null转换为0 1.查询的null转换为0 NVL(Expr1,E ...

  9. NULL、NUL、‘\0’、0以及EOF

    0 is an integer constant, '\0' is a character constant, nul is the name of the character constant. N ...

随机推荐

  1. Linux ssh安全设置

    本文摘要 SSH服务器配置文件是/etc/ssh/sshd_conf.在你对它进行每一次改动后都需要重新启动SSH服务,以便让改动生效.       SSH服务器配置文件是/etc/ssh/sshd_ ...

  2. TreeGrid( 树形表格)

    本节课重点了解 EasyUI 中 TreeGrid(树形表格)组件的使用方法,这个组件依赖于DataGrid(数据表格)组件 一. 加载方式//建立一个 JSON 文件[{"id" ...

  3. [MVC4-基礎] 從資料庫取值顯示在DropDownList中

    剛開始學MVC4,以下是一些基礎的學習筆記! 完成效果像下面這樣,資料來源是既有的Database. 1.Controller public ActionResult Index() { SqlCon ...

  4. 【Linux常用命令(更新)】

    1.ifconfig:查看当前ip,网卡信息 2.df -h:查看文件系统的使用情况,挂载点信息 3.du -sh  /var:查看/var文件夹大小 4.netstat -a:查看网络联机状态 5. ...

  5. polya定理小结

    polya的精髓就在与对循环节的寻找,其中常遇到的问题就是项链染色类问题. 当项链旋转时有n种置换,循环节的个数分别是gcd(n, i); 当项链翻转时有n种置换,其中当项链珠子数位奇数时,循环节的个 ...

  6. MySQL简单查询

    1.普通查询 select * from info; #查询所有内容 select Code,Name from Info #查询某几列 2.条件查询 select * from Info where ...

  7. SelectedNode与e.node的区别

    SelectedNode与e.node的区别 待补.......

  8. AndroidStudio push代码到github

    步骤 1 studio的git配置: 安装好git后启动Androidstudio,打开如下路径File->Settings->Version Control(展开)->git 在P ...

  9. Java如何从HttpServletRequest中读取HTTP请求的body

    首先贴出原文地址,尊重原作者 http://blog.csdn.net/zxygww/article/details/47045055 注意:下面方法已验证通过. HTTP请求中的是字符串数据: // ...

  10. SDWebImage使用——一个可管理远程图片加载的类库

    SDWebImage使用——一个可管理远程图片加载的类库     SDWebImage使用——一个可管理远程图片加载的类库 SDWebImage托管在github上.https://github.co ...