C语言nullptr错误,c/c++中的NULL,nullptr,0

NULL,nullptr与0

0

NULL

C语言中

C++中

隐式类型转换

nullptr

预处理中的条件编译语句

0

在我们的程序中,单纯一个0,在不同的类型中有着不同的意思

0,是一个空字符常量,他在ASCII中的序号就是0,是一个字符串的结束标准

‘0’,表示一个字符'0',他在ASCII中的序号是48

“0”,表示一个字符串"0",他的大小是2,因为在他的末尾还需要有一个0来表示字符串结束的标志

NULL

NULL就是我们在程序中经常见到的空指针,他所在的头文件是stddef.h,他所指向的地址是0x00 00 00 00

f2b59356eb8a9dfaafbcb40200a9d817.png

这个地址默认是一个不能被访问的地址,只要被访问就会报错

581d0f4bba8446e7fd078b89c504244c.png

但是NULL并不是我们所见到的几个基本类型的数据,他在底层中是一个宏,但是对于C语言和C++语言而言,他却是有着不同的定义

C语言中

#undef NULL

#define NULL ((void *)0)

在C语言中,NULL被宏定义为((void *)0)

C++中

vs编译器中的定义

/* Define NULL pointer value */

#ifndef NULL

#ifdef __cplusplus

#define NULL    0

#else  /* __cplusplus */

#define NULL    ((void *)0)

#endif  /* __cplusplus */

#endif  /* NULL */

可以看到,C++为了向下兼容C语言的一些语法,在NULL的定义中,加入了判断

要是C程序,则进行#define NULL ((void *)0)

要是C++程序,则进行#define NULL 0

利用 __cplusplus判断程序的类型

如果一段代码是需要针对C++编写的, 可以使用该宏进行条件编译。__cplusplus的值是为了表示C++的版本。__cplusplus的类型是long int

void Type()

{

#ifdef __cplusplus

printf("This is c++ program %d\n",__cplusplus);

#else

printf("This is c program");

#endif

}

如果没有定义__cplusplus, 那么当前源代码被当作C源代码处理。

如果定义了__cplusplus,那么当前源代码被当中C++源代码处理, 并且输出__cplusplus宏被展开后的字符串。

当我们使用((void *)0)在C++中进行转换的时候,其实是会出错的

460f67e49b74dcd2874477ffae7b6f0d.png

这说明,在C++中是不支持(void*) 0的,这是因为C++中(void*)类型是不支持隐式类型转换的。

因为,C++中存在隐式类型的转换,而当转换的类型是(void*)类型时,对方并不知道这个数据原本的类型是多大,如果在不清楚对方类型的情况下,强制进行转换,很有可能会出现越界访问的情况,或者出现脏数据

隐式类型转换

C++中的基本类型并不是绝对的,部分数据类型之间是可以进行隐式转换的。隐式转换指的是不需要我们进行干预,编译器私下进行的类型转换行为。这个过程是我们看不到的

就像

int a = 1;

char b = 'a';

long long c = a + b;

在第三步中,他其实会把int型的变量a和char型的变量b隐式的转换为double类型的变量

也就是说,隐式类型转换中,他得满足一点就是,只能有低精度的数据类型转为高精度的数据类型。(因为高精度转低精度的话,很容易出现溢出的情况)当然,如果我们确定数据不会溢出,是可以自定义从高精度强转为低精度数据类型的。

但是这种隐式类型的转换,C语言也是支持的,那么为什么C++还不允许(void*)0,别忘了,C++还有一个自定义类型的类

当我们创建一个类,这个类中有6个默认的成员函数,分别是构造,析构,拷贝,赋值运算符重载,还有对普通对象和const对象的取地址操作。

我们写一个类的时候,给他写一个构造函数。构造函数不仅可以构造与初始化对象,他们对于单参数的构造函数,还有着类型转换的作用

class Test

{

public:

Test(int a)

:val(a)

{}

bool isSame(Test obj)

{

return val == obj.val;

}

private:

int val;

};

34e6b83f4d90cd24fde226d915469556.png

在这一步中,我们调用a.isSame(10)进行比较的时候,其实发生了隐式类型转换。

在世界调用中,a.isSame(10)其实是这样进行变换的a.isSame((Test)10),他将我们所传的参数,隐式转换成了Test这个类的类型,然后在底层比较两个类的值是否相同。但是实际我们是想比较Test和int类型数据的不同。

0c3211f3532551aafd1de9b37298449a.png

所以说,如果C++的NULL这个宏支持(void*)0的时候,那么他在隐式类型转换中就会出错,所以C++中的NULL其实就可以看成是一个0

nullptr

在C++11中引入了nullptr这一空指针的类型,至于为什么要引入nullptr

void Fun(int var)

{

cout << "Fun(int var) " << var << endl;

}

void Fun(int* var)

{

cout << "Fun(int* var) " << var << endl;

}

int main()

{

int* p = NULL;

Fun(p);  // -->  void Fun(int* var)

Fun(NULL);// -->  void Fun(int var)

return 0;

}

NULL,本身应该是一个指针的类型,但是在实际调用中却会变成数据类型,这和指针类型发生了二义性。

所以在C++11中,就可以使用nullptr来代替空指针,那么没有nullptr的时候,我们是怎么实现的呢?

const class nullptr_t

{

public:

template

inline operator T*()const

{

return 0;

}

template

inline operator T C::*()const

{

return 0;

}

private:

void operator&()const;

}nullptr = {};

所以说,在C++中,当涉及到空指针的时候,就使用nullptr;NULL就当成0的一个宏定义来使用就o了

预处理中的条件编译语句

#define ,定义一个预处理宏

#undef,取消宏的定义

#if ,编译预处理中的条件命令,相当于C语法中的if语句

#ifdef,判断某个宏是否被定义,若已定义,执行随后的语句

#ifndef ,与#ifdef相反,判断某个宏是否未被定义

#elif ,若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if

#else,与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else

#endif , #if, #ifdef, #ifndef这些条件命令的结束标志.

defined ,与#if, #elif配合使用,判断某个宏是否被定义

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值