Qt:NULL与nullptr的区别(手写nullptr)

news2024/11/16 20:48:32

前言

发现还是有人不知道NULLnullptr的区别,故写此文章。

正文

对于NULL

先看NULL的源码
在这里插入图片描述

我们可以看出这段代码是一个典型的预处理器宏定义块,用于处理 NULL 宏的定义。
先看开头

#if defined (_STDDEF_H) || defined (__need_NULL)
  • 这行代码检查是否已经定义了 _STDDEF_H__need_NULL
    • _STDDEF_H 通常是在包含标准库头文件 <stddef.h> 时定义的宏。
    • __need_NULL 是某些情况下(例如,部分标准头文件仅需要 NULL 定义)会定义的宏。

如果其中一个宏已定义,则代码块会执行。


#undef NULL		/* in case <stdio.h> has defined it. */
  • #undef NULL 取消之前可能在其他头文件(例如 <stdio.h>)中定义过的 NULL,确保后续的定义不会发生冲突。

#if defined(__GNUG__) && __GNUG__ >= 3
#define NULL __null
  • 这一部分是针对 GNU C++ 编译器(G++)版本 3 及以上的特定定义。
    • __GNUG__ 是 G++ 编译器的特定宏,用于检测当前编译器是否为 G++。
    • __null 是 G++ 3.x 及以上版本中的内部表示,用于专门处理空指针的情况。

如果符合条件(G++ 3.x 及以上版本),NULL 被定义为 __null


#else   /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
  • 如果当前编译环境不是 G++ 3.x 或更新版本,且不是 C++,那么 NULL 被定义为 ((void *)0)
    • 在 C 语言中,NULL 通常定义为 (void *)0,表示一个空指针。

#else   /* C++ */
#ifndef _WIN64
#define NULL 0
  • 进入了 C++ 的条件分支。
    • 如果正在编译 C++ 代码,且不是 64 位 Windows 环境(未定义 _WIN64),则 NULL 定义为 0
    • 在 C++ 中,NULL 通常直接定义为 0,因为 C++ 允许整数 0 被隐式转换为指针类型。

#else
#define NULL 0LL
#endif  /* W64 */
#endif  /* C++ */
  • 如果是在 64 位 Windows 环境中,NULL 定义为 0LL,表示一个 64 位的长整数常量(long long)。
    • 在 64 位环境中,使用 0LL 以保证 NULL 的大小与指针的大小一致。

#endif  /* G++ */
#endif  /* NULL not defined and <stddef.h> or need NULL.  */
  • 关闭之前的条件编译语句。
  • #endif 对应前面的 #if,表示条件编译的结束。

#undef	__need_NULL
  • 这行代码取消定义 __need_NULL,确保之后不会再次使用这个宏。

总结

  • 在 GNU C++ 3.x 及以上版本中,NULL 定义为 __null
  • 在 C 语言中,NULL 定义为 (void *)0,表示空指针。
  • 在 C++ 中,NULL 定义为 0,因为 0 可以隐式转换为指针类型。
  • 在 64 位 Windows 环境下,为了确保指针和 NULL 的大小一致,定义为 0LL
  • 由以上我们可知NULL既可以表示0又可以表示(void*)0,这就说明它有二义性。

测试

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int* ptr = NULL;
    int b = 0;
    int* ptr2 = nullptr;
    QString* ptr3 = nullptr;
    if (ptr == 0) {
        qDebug()<<"ptr is null"<<ptr;
    }
    if (b == NULL) {
        qDebug()<<"b is null"<<b;
    }
    if (ptr2 == 0) {
        qDebug()<<"ptr2 is nullptr"<<ptr2;
    }
    if (!ptr3) {
        qDebug()<<"ptr3 is nullptr"<<ptr3;
    }
    return a.exec();
}
运行结果

在这里插入图片描述

对于nullptr

我并没有找到它的源码(如果有找到的兄弟麻烦评论区告知下呗),但是我知道nullptr是一种新的数据类型,就是专门用来表示的一种数据类型。在源码中我只看到它简略的说明
在这里插入图片描述
nullptr的出现就是为了解决NULL即表示0又表示(void*)0的二义性问题。

手写nullptr

const class nullptr_t
{
public:
    // 模板类型转换运算符,可以将 nullptr 转换为任意类型的指针
    template<class T>
    inline operator T*() const
    {
        return 0;  // 返回值为 0,表示空指针
    }

    // 模板类型转换运算符,可以将 nullptr 转换为任意类成员指针
    template<class C, class T>
    inline operator T C::*() const
    {
        return 0;  // 返回值为 0,表示空成员指针
    }
 
private:
    // 重载地址取运算符(&),防止获取 nullptr 的地址
    void operator&() const;
    
} nullptrSelf = {};

使用:

// widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
const class nullptr_t
{
public:
    // 模板类型转换运算符,可以将 nullptr 转换为任意类型的指针
    template<class T>
    inline operator T*() const
    {
        return 0;  // 返回值为 0,表示空指针
    }

    // 模板类型转换运算符,可以将 nullptr 转换为任意类成员指针
    template<class C, class T>
    inline operator T C::*() const
    {
        return 0;  // 返回值为 0,表示空成员指针
    }

private:
    // 重载地址取运算符(&),防止获取 nullptr 的地址
    void operator&() const;

} nullptrSelf = {};


class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void test(int* a);

private:
    void* memberPtr;
};
#endif // WIDGET_H

// widget.cpp


#include "widget.h"
#include "qdebug.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
  memberPtr = nullptrSelf;
  qDebug()<<"memberPtr:"<<memberPtr;
  int* a = nullptrSelf;
  test(a);

}

Widget::~Widget()
{
}

void Widget::test(int* a)
{
    if (a == nullptrSelf) {
        qDebug()<<"a is null "<<a;
    } else {
        qDebug()<<"a is not null "<<a;
    }
}


输出结果

在这里插入图片描述

小结

请指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2143870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git报错,error: bad signature 0x00000000fatal: index file corrupt

报错 git -c diff.mnemonicprefixfalse -c core.quotepathfalse --no-optional-locks checkout daily --progress error: bad signature 0x00000000 fatal: index file corrupt 原因 git 仓库中索引文损坏 处理 1.该备份的先备份 2.删除索引并重置 rm -f .git/index git r…

医学数据分析实训 项目五 分类分析--乳腺癌数据分析与诊断

文章目录 项目六&#xff1a;分类分析实践目的实践平台实践内容&#xff08;一&#xff09;数据理解及准备&#xff08;二&#xff09;模型建立、预测及优化任务一&#xff1a;使用 KNN算法进行分类预测任务二&#xff1a;使用贝叶斯分类算法进行分类预测任务三&#xff1a;使用…

Linux基础3-基础工具4(git,冯诺依曼计算机体系结构)

上篇文章&#xff1a;Linux基础3-基础工具3&#xff08;make,makefile,gdb详解&#xff09;-CSDN博客 本章重点&#xff1a; 1. git简易使用 2. 冯诺依曼计算机体系结构介绍 一. git使用 1.1 什么是git? git是用于管理代码版本的一种工具&#xff0c;我们在如GitHub&#xf…

C++ | (二)类与对象(上)

燕子去了&#xff0c;有再来的时候&#xff1b;杨柳枯了&#xff0c;有再青的时候&#xff1b;桃花谢了&#xff0c;有再开的时候。但是&#xff0c;聪明的&#xff0c;你告诉我&#xff0c;我们的假期为什么一去不复返呢&#xff1f; 目录 一、初识类 1.1 类的定义 1.2 C中…

面试真题-TCP的三次握手

TCP的基础知识 TCP头部 面试题&#xff1a;TCP的头部是多大&#xff1f; TCP&#xff08;传输控制协议&#xff09;的头部通常是固定的20个字节长&#xff0c;但是根据TCP选项&#xff08;Options&#xff09;的不同&#xff0c;这个长度可以扩展。TCP头部包含了许多关键的字…

depcheck 检查项目中依赖的使用情况 避免幽灵依赖的产生

depcheck 检查项目中依赖的使用情况 避免幽灵依赖的产生 什么是幽灵依赖 (幻影依赖) 形成原因 幽灵依赖是指node_modules中存在 而package.json中没有声明过的依赖 但却能够在项目的依赖树中找到并使用的模块 Node.js 的模块解析规则&#xff1a; Node.js 采用了一种非传统的模…

C++速通LeetCode简单第20题-多数元素

方法一&#xff1a;暴力解法&#xff0c;放multiset中排序&#xff0c;然后依次count统计&#xff0c;不满足条件的值erase清除。 class Solution { public:int majorityElement(vector<int>& nums) {int ans 0;multiset<int> s;for(int i 0;i < nums.s…

「iOS」viewController的生命周期

iOS学习 ViewController生命周期有关方法案例注意 ViewController生命周期有关方法 init - 初始化程序&#xff1b;loadView - 在UIViewController对象的view被访问且为空的时候调用&#xff1b;viewDidLoad - 视图加载完成后调用&#xff1b;viewWillAppear - UIViewControll…

给大模型技术从业者的建议,入门转行必看!!

01—大模型技术学习建议‍‍‍ 这个关于学习大模型技术的建议&#xff0c;也可以说是一个学习技术的方法论。 首先大家要明白一点——(任何)技术都是一个更偏向于实践的东西&#xff0c;具体来说就是学习技术实践要大于理论&#xff0c;要以实践为主理论为辅&#xff0c;而不…

换个手机IP地址是不是不一样?

在当今这个信息爆炸的时代&#xff0c;手机已经成为我们生活中不可或缺的一部分。而IP地址&#xff0c;作为手机连接网络的桥梁&#xff0c;也时常引起我们的关注。你是否曾经好奇&#xff0c;换个手机&#xff0c;IP地址会不会也跟着变呢&#xff1f;本文将深入探讨这个问题&a…

Android15之编译Cuttlefish模拟器(二百三十一)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

直流斩波电路

目录 1. 降压斩波电路&#xff08;Buck Converter&#xff09; 2. 升压斩波电路&#xff08;Boost Converter&#xff09; 3. 升降压斩波电路&#xff08;Buck-Boost Converter&#xff09; 4. Cuk斩波电路&#xff08;Cuk Converter&#xff09; 直流斩波电路是一种将直流…

Unity3D下如何播放RTSP流?

技术背景 在Unity3D中直接播放RTSP&#xff08;Real Time Streaming Protocol&#xff09;流并不直接支持&#xff0c;因为Unity的内置多媒体组件&#xff08;如AudioSource和VideoPlayer&#xff09;主要设计用于处理本地文件或HTTP流&#xff0c;而不直接支持RTSP。所以&…

上海人工智能实验室开源视频生成模型Vchitect 2.0 可生成20秒高清视频

上海人工智能实验室日前推出的Vchitect2.0视频生成模型正在悄然改变视频创作的游戏规则。这款尖端AI工具不仅简化了视频制作流程&#xff0c;还为创作者提供了前所未有的灵活性和高质量输出。 Vchitect2.0的核心优势在于其强大的生成能力和高度的可定制性。用户只需输入文字描…

用Matlab求解绘制2D散点(x y)数据的最小外接圆、沿轴外接矩形

用Matlab求解绘制2D散点&#xff08;x y&#xff09;数据的最小外接圆、沿轴外接矩形 0 引言1 原理概述即代码实现1.1 最小外接圆1.2 沿轴外接矩形 2 完整代码3 结语 0 引言 本篇简单介绍下散点数据最小外接圆、沿轴外接矩形的简单原理和matlab实现过程。 1 原理概述即代码实现…

C语言-数据结构 有向图拓扑排序TopologicalSort(邻接表存储)

拓扑排序算法的实现还是比较简单的&#xff0c;我们需要用到一个顺序栈辅助&#xff0c;采用邻接表进行存储&#xff0c;顶点结点存储入度、顶点信息、指向邻接结点的指针&#xff0c;算法过程是&#xff1a;我们先将入度为0的顶点入栈&#xff0c;然后弹出栈顶结点&#xff0c…

使用CUBE_MX使用I2C通信,实现对EEPROM的读写

一、使用CUBE_MX配置 1.配置I2C 2.配置USART1 3.重中之重(在KEIL5打开串口使用的库) 二、KEIL5配置 #include "main.h" #include "i2c.h" #include "gpio.h" #include "usart.h"#include <stdio.h>void SystemClock_Config(vo…

flash_attention简要笔记

优化效果 原来&#xff0c;attention部分的计算量和中间激活占用显存的复杂度都是 O ( N 2 ) O(N^2) O(N2) 计算量部分原来QK矩阵乘和attn_scoreV矩阵乘的计算量&#xff0c;复杂度都是 O ( N 2 ) O(N^2) O(N2)&#xff1b;中间激活因为中间有一个attn_score&#xff0c;所以复…

如何接口对接发送视频短信

随着移动通信技术的飞速发展&#xff0c;视频短信作为一种创新的多媒体信息传递方式&#xff0c;正逐渐成为众多行业不可或缺的沟通工具。它不仅丰富了信息传递的形式&#xff0c;还显著提高了信息接收者的参与度和满意度。 支持免费对接试用乐讯通PaaS平台 找好用的短信平台,选…

数据结构:(OJ141)环形列表

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…