32 位和 64 位之间的指针增量差异

Posted

技术标签:

【中文标题】32 位和 64 位之间的指针增量差异【英文标题】:Pointer increment difference b/w 32-bit and 64-bit 【发布时间】:2011-05-15 17:01:28 【问题描述】:

我试图在 64 位 win7 (amd64) 上运行一些为 32 位 vista (x86) 编码的驱动程序,但它没有运行。经过大量的调试和反复试验,我让它在后者上工作,但我不知道它工作的原因。这就是我所做的:

在许多地方,缓冲区指针指向一个结构数组(在不同的地方不同),为了增加它们,在某些地方使用了这种类型的语句:

ptr = (PVOID)((PCHAR)ptr + offset);

在某些地方:

ptr = (PVOID)((ULONG)ptr + offset);

第二个是退回垃圾,所以我把它们都改成了第一个。但是我在第二个之后在网上找到了许多示例驱动程序。我的问题:

    这些宏在哪里 已定义(谷歌没有太大帮助)? 我知道所有的 P_ 宏都是 指针,为什么要转换指针 到乌龙?这是如何工作的 32 位? PCHAR 显然改变了 宽度根据环境而定。你知道有什么地方可以找到这方面的文档吗?

【问题讨论】:

【参考方案1】:
    它们应该在 WinNT.h 中定义(它们在 SDK 中;手头没有 DDK) ULONG 是无符号长整数;在 32 位系统上,这是指针的大小。所以一个指针 可以来回转换为 ULONG 而不会丢失 - 但在 64 位系统上则不然 (转换值将截断它)。人们投射到 ULONG 以获取基于字节的指针 算术(即使这有未定义的行为,正如您发现的那样) 指针运算始终以基础类型为单位工作,即在 PCHAR 的 CHAR 中;这相当于字节算术 任何 C 书籍都应详细说明指针运算的精确语义。

【讨论】:

【参考方案2】:

此代码在 64 位上失败的原因是它正在将指针转换为 ULONG。 ULONG 是 32 位值,而 64 位上的指针是 64 位值。因此,每当您使用 ULONG 强制转换时,您都会截断指针。

假设 PCHAR 被定义为 char * 的 PCHAR 转换很好,前提是其目的是将指针增加一个明确的字节数。

两个宏的目的相同,但只有一个在指针大于 32 位时有效。

指针算法是这样工作的。如果你有:

T *p;

你做到了:

p + n;

(其中n是一个数字),那么p的值将改变n * sizeof(T)

举个具体的例子,如果你有一个指向 DWORD 的指针:

DWORD *pdw = &some_dword_in_memory;

然后你给它加一个:

pdw = pdw + 1;

那么您将指向下一个 DWORD。 pdw 指向的地址将增加sizeof(DWORD),即4 个字节。

您提到的宏使用强制转换导致它们应用的地址偏移量乘以不同的数量。这通常只在已传递 BYTE(或 char 或 void)缓冲区但知道其中的数据实际上是其他类型的低级代码中完成。

【讨论】:

重新阅读您的问题,我注意到它正在转换为 ULONG 而不是 ULONG*,因此我在答案顶部添加了部分,我认为这是最重要的部分。其余的只是背景信息。【参考方案3】:

ULONG 在 Windows SDK 的 WinDef.h 中定义并且始终为 32 位,因此当您将 64 位指针转换为 ULONG 时,会将指针截断为 32 位。

【讨论】:

以上是关于32 位和 64 位之间的指针增量差异的主要内容,如果未能解决你的问题,请参考以下文章

32 位和 64 位进程之间的 memcpy 性能差异

对于intptr_t和uintptr_t的理解

绘制熊猫时间增量

TestComplete 64位和32位之间的区别

不同位大小的 POS 上的数据类型之间是不是存在差异?

boost::interprocess 32 位和 64 位进程之间的共享内存