linux内核中的 指针 和 unsigned long
1.指针的来源
方便引用一个内存地址。
给定一个内存地址,CPU就可以取出该地址的数据。
给定一个内存地址,CPU就可以写入该地址一个值。
2.指针的定义:
指针的本质其实也是一个数据类型,和char, short, int 等一样都属于c语言中的基本类型,所以大小也确定了(与它是什么类型无关),32位系统为4个字节,64为系统为8个字节。
无论指针什么类型(大小以确定),它存放的都是一个地址,只不过这个地址存放不同数据类型而已。
指针变量与其它变量(如int)相似,也有两个方面即:值 和 类型(所指向的数据类型)
值:表示某个对象的地址(位置)。
类型:表示那个地址(位置)上所存储对象的类型。
备注:指针的强制类型转换不会改变真实的指针,只是告诉编译器以新的数据类型来看待被指向的数据。
3.字长和数据类型
在支持Linux的体系结构中,能够由机器一次完成处理的数据称之为字,指明了指针数据的 nominal size。虚拟地址是以这样的一个字来编码,所以字长决定的最重要的系统参数就是虚拟地址空间的最大大小。即:对于一个字长位n的机器,虚拟地址的范围位 0 ~ 2n-1 ,程序最多访问2n个字节。
处理器通用寄存器的大小和他的字长是相同的。long类型总是等于机器的字长,也等于指针的大小。
但是long和int 大小没办法保证一样。比如:
Linux支持的64位体系架构 long 8个字节,int 4个字节。
Linux支持的32位体系架构 long 4个字节,int 4个字节
因此不要假设 long 和 int 长度相等,也不要假设指针和int 长度相等。
备注:上面只是讨论支持Linux的体系架构
4.Linux内核为什么常用unsigned long来替代指针?
因为指针也是一种基本类型,所以大小是确定的,32位系统下为4个字节,由于地址的值不能为负,所以指针的值的范围为 0 - (2^32-1),与unsigned long大小,值的范围一样。
所以32位系统下指针的最大寻址范围为2^32-1,即4G(所以32位系统虚拟地址为0 - 4G)。
64位系统下大小为8个字节,与unsigned long大小,值的范围一样。
可见指针与unsigned long 大小,值的范围也一样。(但意义不一样,只是值一样)
指针与unsigned long 大小一样,值的范围也一样。
当linux内核只关心这个地址的值,用于去运算、查找、对比,而不是关心通过这个地址去访问内存,这个时候,内核经常用unsigned long来替代指针。
当然内核在部分地方也用 unsigned long 去访问该地址内存的内容,将其 unsigned long 强制转化为 一个指针。
比如:
char *tmp = (char*)__get_free_page(GFP_TEMPORARY);
#define __get_free_page(gfp_mask) \
__get_free_pages((gfp_mask), 0)
/*
* Common helper functions.
*/
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
{
struct page *page;
/*
* __get_free_pages() returns a 32-bit address, which cannot represent
* a highmem page
*/
VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);
page = alloc_pages(gfp_mask, order);
if (!page)
return 0;
return (unsigned long) page_address(page);
}
EXPORT_SYMBOL(__get_free_pages);
__get_free_page 调用伙伴系统接口(alloc_pages)分配一页物理内存,返回这页物理内存的内核虚拟地址的首地址,类型unsigned long,当要去访问该内核虚拟地址时,将其转化为指针(char*) 再去进行内存地址访问。
5.c demo
#include <stdio.h>
int main()
{
char buf[] = "abcdef";
char *p = buf;
//将指针转换为unsigned long,接下来就可以对该地址去运算、查找、对比,而不是关心通过这个地址去访问内存
unsigned long val = (unsigned long)p;
//将unsigned long转为指针,通过这个地址去访问内存
char *pp = (char *)val;
printf("pp[0]: %c\n", pp[0]);
return 0;
}
参考资料
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)