NULL

  • 在C/C++中,NULL是一个特殊的常量,可以被赋值(隐式转换)给任意指针类型!

  • 在C中,NULL被定义成一个0值常量表达式或者该表达式被转型为void*,具体由实现决定
    但语法上允许下面用法

    1
    2
    int *pi1 = 0; // ok
    int *pi2 = (void*)0; // ok

    在C++11之前,32位系统中,NULL被定义成0,64位被定义为0LL,这样在一定场景下会导致歧义!

    C++11之后采用nullptr,不支持(void*)0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #ifndef NULL
    #ifdef __cplusplus
    #ifndef _WIN64
    #define NULL 0 // 32bit
    #else
    #define NULL 0LL // 64bit
    #endif /* W64 */
    #else
    #define NULL ((void *)0)
    #endif
    #endif

    int *pi1 = 0; // ok
    int *pi2 = (void*)0; // error!
    int *pi3 = 1; // error!
    void DoSomething(int x);
    void DoSomething(char* x);
    DoSomething(NULL); // g++ 5.1.0: error: call of overloaded 'DoSomething(NULL)' is ambiguous

    std::vector<int*> v(10);
    // 模板根据NULL推断类型为long long int,而v对应的却是int*!
    std::fill(v.begin(), v.end(), NULL); // error: error: invalid conversion from 'long long int' to 'int*'

void*

在C中,void*从或者向其他类型指针隐式转换,但在C++中,不允许void*隐式转换为其他类型指针!

1
2
3
void *pv;
int *pi = pv; // C中合法,C++中不合法
pv = pi; //
1
2
3
4
void *pv;
// int *pi = pv; // error!
int *pi = reinterpret_cast<int*>(pv);
pv = pi;

为什么C++中采用#define NULL 0,而不支持#define NULL ((void *)0)呢?

在C中,假设开发人员知道他们所做的事,允许void*隐式转换是为了方便程序开发。

而在C++中,为了保证类型安全,不建议使用C中的强制类型转换,以及void*隐式转换(从语法层禁止!)
因为C++中,为了支持类,多态,类型之间任意转换,是很容易导致错误的!

假设允许void*隐式转换:

1
2
void *pa = new A;
B *pb = pa;

类似这样的代码不会发出任何警告,而这样的错误定位起来非常麻烦!

参考

  1. Why must I use a cast to convert from void*?
  2. http://stackoverflow.com/questions/7016861/why-are-null-pointers-defined-differently-in-c-and-c
  3. http://en.cppreference.com/w/c/language/conversion#Pointer_conversions
  4. http://en.cppreference.com/w/cpp/types/NULL
  5. http://softwareengineering.stackexchange.com/questions/275712/why-arent-void-s-implicitly-cast-in-c
  6. C++ 4.10.1

留言

2016-10-28