c++11起空指针必须用NULLptr:它是独立类型std::nullptr_t,专用于指针上下文,避免重载歧义、类型退化和模板推导错误,且无需头文件;null是宏,定义不稳定,易引发隐式转换问题。

空指针在C++里必须用 nullptr,不是 NULL 或 0
现代C++(C++11起)规定:空指针字面量唯一合法写法是 nullptr。它是个独立类型(std::nullptr_t),专用于指针上下文,不会被误认为整数。
常见错误现象:NULL 在有些头文件里定义为 0,在函数重载时可能调用错版本;int* p = 0; 虽能编译,但语义模糊,且无法区分“空指针”和“整数字面量0”。
-
nullptr只能赋给指针类型(包括智能指针),编译器会严格检查 -
NULL是宏,通常展开为0或((void*)0),在C++中后者不合法,前者导致类型退化 - 函数重载场景下差异最明显:
void f(int); void f(char*); f(NULL);会调f(int),而f(nullptr)正确匹配f(char*)
nullptr 和 NULL 的兼容性与头文件无关
nullptr 是语言关键字,不需要任何头文件;NULL 来自 <cstddef></cstddef> 或其他C头文件(如 <stdio.h></stdio.h>),但它的定义不稳定——标准只要求它是空指针常量,没规定具体形式。
使用场景:跨平台或混用C/C++代码时,NULL 可能因编译器/标准库实现不同而行为不一;nullptr 则始终一致。
立即学习“C++免费学习笔记(深入)”;
- 即使包含
<cstddef></cstddef>,也不该用NULL初始化指针 - 模板推导中
nullptr能正确推成std::nullptr_t,NULL推成int或long,容易出错 - 在
constexpr上下文中,nullptr是字面量常量,NULL不一定(取决于其宏定义)
判断空指针别用 == NULL,统一用 == nullptr
虽然 p == NULL 通常能通过编译,但它掩盖了类型意图,且在自定义类重载 operator== 时可能意外触发非指针逻辑。
性能上无差异,但可读性和静态检查收益明确:编译器对 nullptr 的比较有更好诊断能力(比如检测是否对非指针类型做 == nullptr)。
- 推荐写法:
if (ptr == nullptr),而不是if (!ptr)或if (ptr == NULL) -
!ptr虽简洁,但依赖隐式转换,对某些智能指针(如自定义的)可能失效或不直观 - 静态分析工具(如 clang-tidy)默认警告
== NULL,鼓励迁移到== nullptr
老代码里遇到 NULL 怎么安全替换
直接全局替换风险高——有些地方 NULL 实际用作整数零(比如数组索引、errno赋值),不能一概而论。
实操建议分三步走:
- 先用编译器警告定位真正用作空指针的地方:开启
-Wzero-as-null-pointer-constant(Clang/GCC) - 只替换出现在指针声明、初始化、比较、return语句右侧的
NULL - 特别注意宏定义内部、条件编译块、第三方头文件包含路径中的
NULL,这些不建议动
一个典型安全替换示例:char* buf = NULL; → char* buf = nullptr;;但 memset(p, NULL, n); 里的 NULL 是整数0,应改为 0。
最易被忽略的是函数参数传递:比如 foo(NULL),必须确认 foo 声明中该参数确实是指针类型,否则改了反而引入新bug。