C 为什么linux内核(经常)在无符号长对象中保存指针

C 为什么linux内核(经常)在无符号长对象中保存指针,c,pointers,linux-kernel,unsigned-integer,C,Pointers,Linux Kernel,Unsigned Integer,我经常看到(例如在Linux内核中)使用unsigned long来保存指针。考虑到指针的大小可能大于整数类型(包括long),我想知道这是什么原因 在Linux用户空间应用程序中,将指针保留在unsigned long而不是uintpttr\t中是否可以移植?(尽管我知道uintptr\u t保证从void*转换为uintptr整数并返回而不丢失信息) 谢谢 在Linux用户空间应用程序中,将指针保留在unsigned long而不是uintpttr\t中是否可以移植?(尽管我知道uintpt

我经常看到(例如在Linux内核中)使用
unsigned long
来保存指针。考虑到指针的大小可能大于整数类型(包括long),我想知道这是什么原因

在Linux用户空间应用程序中,将指针保留在
unsigned long
而不是
uintpttr\t
中是否可以移植?(尽管我知道
uintptr\u t
保证从
void*
转换为
uintptr
整数并返回而不丢失信息)

谢谢

在Linux用户空间应用程序中,将指针保留在
unsigned long
而不是
uintpttr\t
中是否可以移植?(尽管我知道
uintptr\u t
保证从
void*
转换为
uintptr
整数并返回而不丢失信息)

“是”的意思是,它将在Linux的任何当前端口上工作,并且很可能在将来工作。但是为什么呢?还有一个非常好的typedef也指定了它的意图:
uintptr\u t
——它还使您的代码可以移植到Win64

uintptr\u t
是C99的发明,Linux比C99早很多年。当时,没有约定指定一个足够宽的整数来容纳指针,但当时也没有
unsigned long
,除了编译器扩展名,所以
unsigned long
是所有你可以合理地期望容纳指针的东西,如果有的话,就是这样。到目前为止,对于任何运行Linux的新体系结构,都需要为
long
选择类型,以便它足够宽,可以容纳指针
size\t


当64位窗口出现时,太多东西依赖于
无符号长
的某种表示,它仍然是32位,而不是保持指针所需的类型。据我所知,目前所有相关平台仅在Win64上
unsigned long
的宽度不足以容纳指针。

内核代码和用户空间代码不是相同的环境。在内核代码中使用“unsigned long”作为指针在现代编译器中可能是一种值得怀疑的做法,但大部分代码都是很久以前编写的,而这些代码的作者对他们正在做的事情有很好的线索。您的问题的答案是否定的,它对于内核或用户模式代码来说是不可移植的。如果您检查内核代码,您将发现许多条件编译源代码的实例,这些实例处理编译器和目标体系结构特定的问题,在大多数用户空间代码中您不必求助于这些问题。请参阅:查看“技术选择”部分中的表。对于所有内存型号,除了
LLP64
(仅由microsoft编译器[AFAIK]使用)之外,
long
的大小始终与指针的大小相同。MS选择
LLP64
的唯一原因是,在DOS时代,
int
是16位的。为了得到32个数字,他们使用了
long
[
long
]。当他们转到64位时,为了保持向后兼容性,他们使用了
LLP64
。但是,如果H/W arch支持64位(例如intel),则不需要
LLP64
。因此,内核也很好,内核不使用(例如,
uint32_t
),而是使用
u32
[和其他]。他们早在stdint.h出现之前就开始编写代码了。而且,就我个人而言,我更喜欢u32,因为它比较短。无论如何,内核有大约2100万行代码。他们有自己的惯例。@CraigEstey,谢谢你的反馈。LP64内存模型是否也适用于gcc和Linux?如果您阅读了这些标准,我想您会发现,没有要求long始终足够大以容纳指针。恰好是针对英特尔(IMS)和GNU编译器(可能是其他编译器)。后者是Linux内核编译IIRC中唯一真正重要的一个。正如已经指出的那样,内核已经进化了几十年,并且经过了C标准的多次迭代,但是一个不变的因素是GNU编译器,它可能使Linux从一开始就成为可能。