“解引用“空指针一定会导致段错误吗?

news/2024/11/24 2:14:07/

可能有些朋友看见这个标题第一反应是嵌入式的某些内存中,0地址也是可以被正常访问的,所以对0地址的解引用不会发生错误,但我要说的情况不是这个,而是指一个真正的空指针,不仅是c/c++中的0,(void*)0,NULL,还有nullptr,一个真正的空指针.

在c语言中,想获得某结构体的成员变量相对偏移,可以使用offsetof宏,其实现可能是:

#define offsetof(s,m)   (size_t)&(((s*)0)->m)

可以发现:

  1. 先将0转换为指向s的指针
  2. 使用->解引用,获取到m变量
  3. 使用&取地址,获得一个指向m的指针
  4. 将指针转换为size_t,即为m的偏移

从这个例子可以发现,对于0地址,发生了一次"解引用",然而并没有"segmentation fault",为什么呢?其实呢,这个解引用被优化了,编译器看到这句时,并没有发生实际的解引用而获得到了m的地址,是一个真正的编译器开洞才能实现的功能.(如有错误,诚请斧正)

你可以这样定义自己的offsetof

#undef offsetof
#define offsetof(s,m)	(size_t)&(((s*)NULL)->m)
// 或
#undef offsetof
#define offsetof(s,m)	(size_t)&(((s*)nullptr)->m)

你会发现,也是可以正常工作的,至少gcc的c++14之前是可以的,gcc的c++14后,
对于non-POD类型,这个宏将可能可能导致未定义的问题.注意,在cppreference中说的是从c++11开始,对于non-POD类型使用offsetof宏将导致未定义行为.
no-invalid-offsetof

gcc中的offsetof是这样定义的:Support for offsetof

#define offsetof(type, member) __builtin_offsetof (type, member)

可以发现,果然是内置的编译器开洞实现的功能.

综上,解引用一个空指针,不一定会导致段错误.
在c++中,想获得类或结构体成员的偏移量,不要使用offsetof,而应该使用&ClassName::MembersName,例如&test::str,就获取到了str的偏移

#include <vector>
#include <iostream>
class test{
public:float float_number = 3.14;int int_number = 456;std::string str = "789";
};template<typename T>
void print_member(const test* class_ptr,T test::* member_offset){printf("offset of member is %p,content is ",member_offset);std::cout << class_ptr->*member_offset << std::endl;
}int main(){test t;print_member(&t,&test::int_number);print_member(&t,&test::str);
}
/*
output:
offset of member is 0x4,content is 456
offset of member is 0x8,content is 789
*/

http://www.ppmy.cn/news/1031562.html

相关文章

定长内存池设计ConcurrentMemoryPool

原理 还回来的内存用链表串联起来&#xff0c;称为自由链表 内存块自身进行链接&#xff0c;前四个字节存下一个的地址 结构 template<class T> class ObjectPool { public:T* New(){} private:char* _memory nullptr; //方便切割void* _freeList nullptr; };第一步…

.NET 6.0 重启 IIS 进程池

在 .NET 6.0 中&#xff0c;你可以使用 Microsoft.Web.Administration 命名空间提供的 API 来管理 IIS 进程池并实现重启操作。以下是一个示例代码&#xff0c;展示如何使用 .NET 6.0 中的 Microsoft.Web.Administration 来重启 IIS 进程池&#xff1a; using Microsoft.Web.A…

高并发内存池项目(C++实战项目)

项目介绍 项目来源 本项目实现了一个高并发内存池&#xff0c;参考了Google的开源项目tcmalloc实现的简易版&#xff1b;其功能就是实现高效的多线程内存管理。由功能可知&#xff0c;高并发指的是高效的多线程&#xff0c;而内存池则是实现内存管理的。 tcmalloc源码 项目…

【高频面试题】常见技术场景

文章目录 单点登录这块怎么实现的权限认证是如何实现的上传数据的安全性怎么控制&#xff1f;你们项目中日志怎么采集的查看日志的命令生产问题怎么排查怎么快速定位系统的瓶颈 单点登录这块怎么实现的 单点登录的英文名叫做&#xff1a;Single Sign On&#xff08;简称SSO&am…

设计师常用的UI设计软件推荐

如今&#xff0c;随着互联网时代设计岗位的演变&#xff0c;近年来出现了一位新兴而受欢迎的专业UI设计师。对于许多对UI设计感兴趣或刚刚接触UI设计的初学者来说&#xff0c;他们不禁想知道&#xff0c;成为一名优秀的UI设计师需要掌握哪些UI软件&#xff1f;今天&#xff0c;…

Python爬虫——selenium的安装和基本使用

1.什么是selenium&#xff1f; selenium是一个用于web应用程序测试的工具selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样支持通过各种driver&#xff08;FrifoxDriver&#xff0c;ItenrentExploreDriver&#xff0c;OperaDriver&#xff0c;ChromeDrive…

CF 1859E Maximum Monogonosity 绝对值的巧妙处理和状态设计

CF 1859E 题意:给你两个长度为 n n n的数组 a a a, b b b&#xff0c;选择一些点对 ( l i , r i ) (l_i,r_i) (li​,ri​)。 每个点对对答案产生贡献 a b s ( b l i − a r i ) a b s ( b r i − a l i ) abs(b_{l_i}-a_{r_i})abs(b_{r_i}-a_{l_i}) abs(bli​​−ari​​)abs(…

配置网络设置和修改主机名

bash 题目&#xff1a; 在 node1 上配置网络&#xff0c;要求如下&#xff1a; 主机名&#xff1a;node1.domain8.rhce.cc IP地址: 172.25.250.10/24 ##注意掩码 网关&#xff1a; 172.25.250.250 DNS&#xff1a; 172.25.250.250 ##名称服务器 做法&#xff1a; nmtui 回车…