【嵌入式】指针与整数的桥梁、跨平台编程的黄金钥匙:揭开 uintptr_t 和 intptr_t 的神秘面纱

news2025/1/10 18:46:33

目录

    • 一、intptr_t 和 uintptr_t 详解
    • 二、适用场景
    • 三、示例
    • 四、写在最后

一、intptr_t 和 uintptr_t 详解

intptr_t 和 uintptr_t,这两个数据类型是ISO C99定义的。主要用于处理指针和整数之间的转换。它们在需要将指针转换为整数进行操作,或者将整数转换回指针的场景中非常有用。

具体代码在linux平台的/usr/include/stdint.h头文件中,见下图。
stdint.h
先介绍一下上图中__WORDSIZE 的含义

__WORDSIZE的含义
在计算机科学中,__WORDSIZE是一个与处理器相关的编译器宏,它通常用于标识目标处理器的数据字长,即处理器内部操作的数据宽度。这个宏的值通常等于处理器的指令集架构(ISA)中规定的数据宽度,比如32位或64位。在不同的编译器和操作系统中,__WORDSIZE的具体含义和使用可能有所不同。

在64位系统中
在64位系统中,__WORDSIZE通常被定义为64,表示处理器可以处理64位的数据。这意味着,64位的寄存器可以存储64位整数,指针也可以表示64位的虚拟地址空间。

在32位系统中
而在32位系统中,__WORDSIZE则被定义为32,表示处理器处理的数据宽度为32位。这包括32位的通用寄存器和32位的虚拟地址空间。

__WORDSIZE在编程中的应用
了解__WORDSIZE的值对于编写高效的代码非常重要。例如,在编译代码时,可以根据__WORDSIZE的值来优化数据类型和操作,以充分利用处理器的性能。在某些情况下,程序员可能会根据__WORDSIZE的值来决定是否使用64位整数运算或者指针操作。

根据上图 stdint.h 中的代码,我们可以看到
当是64位系统的情况下

typedef long int  intptr_t;
typedef unsigned long int  uintptr_t;

不是64位系统的情况下

typedef int  intptr_t;
typedef unsigned int  uintptr_t;

为什么会这么定义呢?
先看下不同的数据类型在不同字长机器上长度大小。

系统位数charshortintlong指针
161个字节8位2个字节16位2个字节16位4个字节32位2个字节16位
321个字节8位2个字节16位4个字节32位4个字节32位4个字节32位
641个字节8位2个字节16位4个字节32位8个字节64位8个字节64位

由上表可以看到,指针在32位平台和64位平台下指针均与long 类型的长度一致,然而在16位机器上,long为4个字节,而指针为2个字节。

因此,就可以发现intptr_t和uintptr_t定义的巧妙之处:在64位机器上,intptr_t为long int,uintptr_t为unsigned long int。而在非64位机器上,intptr_t为int,uintptr_t为unsigned int。

这样就可以保证intptr_t和uintptr_t的长度与机器的指针长度一致,因此在进行整数与指针的相互转换时可以用intptr_t和uintptr_t进行过渡。

二、适用场景

适用场景主要包括以下几种:

1、指针与整数的安全转换

存储指针值: 如果需要存储指针的值,尤其是在需要进行序列化或者临时存储时,使用 uintptr_t(无符号类型)能够确保不会出现符号相关的问题。

与算术运算结合: 若需要对指针值进行算术运算,比如加减操作,使用 intptr_t 可以将指针转换为整型后进行有符号运算,方便按需调整内存地址。

2、数据结构的实现

自定义数据结构: 在实现链表、哈希表、树等数据结构时,可以使用 intptr_t 或 uintptr_t 来存储节点的指针值。这使得在处理指针和索引时能够避免类型不匹配的问题。

3、指针的自由操作

位操作: 在需要进行位级操作时,可以将指针转换为 uintptr_t,这样可以以无符号整数的形式使用,加快处理效率。同时,避免了由于有符号运算可能导致的错误。

4、在底层与操作系统交互

系统调用和库函数: 在与操作系统的底层 API 或特定库函数交互时,常常需要将指针类型转为整数。此时,使用 intptr_t 和 uintptr_t 能够保证所需指针值的安全传递。

5、跨平台兼容性

增强代码的可移植性: 在编写需要跨平台运行的程序时,使用这两个类型能够保证指针和整型之间的转换在不同的平台上都能保持稳定性。一些平台可能在指针大小上有所不同,使用这两个类型可以避免因数据大小导致的错误。

6、处理回调和异步操作

上下文处理: 在使用回调函数或异步通知时,传递上下文信息时可以将指针转换为 intptr_t 或 uintptr_t。这样在处理时,可以将指针信息安全地从一个上下文传递到另一个上下文。

三、示例

下面举两个示例,来演示如何使用intptr_t 和 uintptr_t。

示例1

demo0.c

#include <stdio.h>
#include <stdint.h>
 
int main(int argc, char *argv[]){
	int a = 9;    
	int *p = &a;
	
	int ptr = (int )p;
	printf("Pointer as integer: %d\n",ptr);
	return 0;
}

编译时候gcc给出警告

在这里插入图片描述

Wpointer-to-int-cast 意思是将指针转换为整型,二者大小不匹配,

修改后的正确代码如下

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[]) {
    int value = 42;
    int *p = &value; // 指向整型的指针

    // 正确的转换:将指针转换为 uintptr_t
    uintptr_t ptr = (uintptr_t)p; 
    printf("Pointer as integer: %lu\n", ptr);
    return 0;
}

示例2

demo1.c

#include <stdio.h>
#include <stdint.h>

void displayPointerInfo() {
    int value = 42;                // 一个整型变量
    int *ptr = &value;            // 指向整型变量的指针

    // 使用 intptr_t 将指针转换为有符号整数
    intptr_t intptr_value = (intptr_t)ptr;  
    printf("Original pointer as intptr_t: %ld\n", intptr_value);

    // 使用 uintptr_t 将指针转换为无符号整数
    uintptr_t uintptr_value = (uintptr_t)ptr; 
    printf("Original pointer as uintptr_t: %lu\n", uintptr_value);

    // 修改原指针的值
    *ptr = 100;
    printf("Modified value: %d\n", *ptr);

    // 通过从 intptr_t 恢复指针
    int *retrieved_ptr1 = (int *)intptr_value;
    printf("Retrieved value from intptr_t: %d\n", *retrieved_ptr1);

    // 通过从 uintptr_t 恢复指针
    int *retrieved_ptr2 = (int *)uintptr_value;
    printf("Retrieved value from uintptr_t: %d\n", *retrieved_ptr2);
}

int main() {
    displayPointerInfo(); // 调用示例函数
    return 0;
}

编译运行

在这里插入图片描述

四、写在最后

关于 intptr_t 和 uintptr_t 的总结完毕,如有问题,也欢迎随时交流。

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

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

相关文章

spring boot入门案例

一、案例需求 请求Controller中的方法&#xff0c;并将返回值响应到页面 二、代码实现 1.依赖管理——pom.xml文件 &#xff08;1&#xff09;引入 &#xff08;2&#xff09;引入依赖集合 &#xff08;3&#xff09;引入插件&#xff1a;为了方便运行&#xff0c;将project…

[Meachines] [Medium] Haircut Curl命令注入+TRP00F自动化权限提升+Screen4.5.0权限提升

信息收集 IP AddressOpening Ports10.10.10.24TCP:22,80 $ nmap -p- 10.10.10.24 --min-rate 1000 -sC -sV ORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 e9:75:c1:e4:b3:63…

驱动开发系列10 - Linux Graphics 图形栈介绍

目录 一:Linux 图形栈总体结构 1. 整体图形栈: 2. 现代3D图形栈: 二:Xorg 介绍 Xorg 概述: Xorg的发展历史: Xorg绘制原理: Xorg的缺点: 三:Wayland 介绍 一:Linux 图形栈总体结构 1. 整体图形栈: 应用程序->桌面环境->GUI框架->Display Client->Displ…

探索边缘计算与云计算之间的区别

IT管理员不需要在边缘和云之间进行选择&#xff0c;但需要了解每种技术的优缺点&#xff0c;以便最好地将它们融入到企业运营中。 许多组织使用云作为其整体IT平台的一部分。资源管理的灵活性和更高的整体利用率的承诺可以等同于节省成本。 此外&#xff0c;对许多人而言&…

聚焦巴黎奥运会 | AI技术如何成为赛场上的智能明星?

备受关注的2024年巴黎奥运会已圆满落幕&#xff01; 本届巴黎奥运会不仅是全球瞩目的体育盛事&#xff0c;更是展示中国科技创新实力的重要舞台。从精彩的赛事转播到精密的比赛设备&#xff0c;再到先进的场馆建设&#xff0c;中国的"黑科技"正伴随着中国运动员的矫健…

达梦DSC集群部署.docx

1. 前期规划 1.1. 集群规划 节点1节点2业务服务名DSC业务IP192.168.25.101192.168.25.102内部数据交换网络IP10.10.10.110.10.10.2dmdcr_cfgCSSDCR_EP_NAMECSS0CSS1DCR_EP_HOST10.10.10.110.10.10.2DCR_EP_PORT11286ASMDCR_EP_NAMECSS0CSS1DCR_EP_HOST10.10.10.110.10.10.2DC…

服务器数据恢复—raid5阵列热备盘未全部启用导致阵列崩溃的数据恢复案例

服务器存储数据恢复环境&#xff1a; 一台EMC某型号存储中有一组RAID5磁盘阵列。该raid5阵列中有12块硬盘&#xff0c;其中2块硬盘为热备盘。 服务器存储故障&#xff1a; 该存储raid5阵列中有两块硬盘离线&#xff0c;只有1块热备盘启用替换掉其中一块离线盘&#xff0c;另外…

如何让RStudio使用不同版本的R

下面内容摘录自&#xff1a; 专栏问答&#xff1a;管理和选择不同的R&#xff0c;如何做好R的笔记_rstudio如何在不同的r版本中进行切换-CSDN博客 欢迎订阅我们专栏 问题一&#xff1a;如何发现RStudio需要安装和使用不同版本的R。这是为什么呢&#xff1f; R允许用户在同一系统…

Spring容器启动的过程(main)

大体流程如下 1、初始化 首先&#xff0c;Spring会通过用户提供的配置信息&#xff08;例如XML文件或者注解&#xff09;来初始化一个BeanFactory&#xff0c;这个BeanFactory是Spring容器的核心&#xff0c;它负责创建和管理所有的Bean。 2、读取配置生成并注册BeanDefini…

单点Redis中面临哪些问题

我的后端学习大纲 我的Redis学习大纲 1.面试&#xff1a;请说下在单点Redis中面临哪些问题&#xff1a; 1.1.单点Redis的问题&#xff1a; 1.数据丢失问题&#xff1a;Redis是内存存储&#xff0c;服务重启可能会丢失数据 2.并发能力问题&#xff1a;单节点Redis并发能力虽然…

springboot系列十二:拦截器和文件上传

文章目录 基本介绍拦截器应用实例需求分析代码实现注意事项和细节 文件上传需求说明代码实现注意事项和细节课后扩展 基本介绍 1.在Spring Boot项目中, 拦截器是开发中常用手段, 要来做登陆验证, 性能检查, 日志记录等. 2.基本步骤: √ 编写一个拦截器实现HandlerInterceptor…

【简单】 猿人学web第一届 第3题 罗生门

请求逻辑分析 数据接口为https://match.yuanrenxue.cn/api/match/3?page1 这一题的 请求参数 与 cookie 都没有加密参数 每次请求数据接口前都会请求 jssm 接口 requests 照着请求逻辑去请求&#xff0c;发现是失败的&#xff08;数据接口返回包含 js标签 代码&#xff09;…

Unity数据持久化 之 Json序列化与反序列化

语法规则可以看这篇文章&#xff1a;Unity数据持久化 之 Json 语法速通-CSDN博客 Q:Unity是通过什么来对Json文件进行处理的&#xff1f; A:JsonUtility&#xff1a;Unity 提供了 JsonUtility 类&#xff0c;用于将对象序列化为 JSON 字符串或将 JSON 字符串反序列化为对象。…

从 MySQL 迁移到 TiDB:使用 SQL-Replay 工具进行真实线上流量回放测试 SOP

导读 在 MySQL 迁移至 TiDB 的过程中&#xff0c;兼容性和性能验证至关重要。SQL-Replay 是一款实用工具&#xff0c;用于评估数据库的兼容性和性能&#xff0c;支持日志解析、查询回放、性能测量和报告生成等功能。 本文介绍了 SQL-Replay 工具的安装和使用步骤&#xff0c;…

基于springboot的医院后台管理系统的设计与实现

TOC springboot167基于springboot的医院后台管理系统的设计与实现 第1章 绪论 1.1 研究背景 互联网概念的产生到如今的蓬勃发展&#xff0c;用了短短的几十年时间就风靡全球&#xff0c;使得全球各个行业都进行了互联网的改造升级&#xff0c;标志着互联网浪潮的来临。在这…

【C语言】格式化输出占位符及其标志字符详解(基于ISO/IEC 9899:2024)

目录 C语言格式化输出占位符及其标志字符详解&#xff08;基于ISO/IEC 9899:2024&#xff09;1. 格式说明符的基本结构1.1 标志字符&#xff08;Flags&#xff09;示例代码 1.2 宽度&#xff08;Width&#xff09;示例代码 1.3 精度&#xff08;Precision&#xff09;示例代码 …

一键换肤(Echarts 自定义主题)

一键换肤&#xff08;Echarts 自定义主题&#xff09; 一、使用官方主题配置工具 官方主题配置工具&#xff1a;https://echarts.apache.org/zh/theme-builder.html 如果以上主题不满足使用&#xff0c;可以自己自定义主题 例如&#xff1a;修改背景、标题等&#xff0c;可…

字节跳动飞书一面0715

进程间通信方式有哪些 1、管道通信&#xff0c;分为匿名管道和有名管道&#xff0c;匿名管道只能在有亲缘关系如父子进程间使用。有名管道可以允许无亲缘关系进程间的通信。它们都是半双工的通信方式&#xff0c;数据只能单向流动。 2、消息队列&#xff0c;用内核中的链表实现…

深入理解WAF(Web应用防火墙)及其安全防御策略

随着互联网的普及和发展&#xff0c;Web应用也面临着越来越多的安全威胁&#xff0c;如SQL注入、跨站脚本&#xff08;XSS&#xff09;、跨站请求伪造&#xff08;CSRF&#xff09;等。这些威胁不仅可能造成数据泄露&#xff0c;还可能导致业务中断和品牌受损。本文将以快快网络…

JavaEE 第9节 阻塞队列详解

一、概念 阻塞队列是在普通队列&#xff08;先进先出的数据结构&#xff09;的基础上增加了阻塞属性的特殊队列 1&#xff09;当阻塞队列空的时候&#xff0c;如果继续出队元素会进入阻塞状态&#xff0c;直到其他线程入队元素。 2&#xff09;当阻塞队列满的时候&#xff0c;…