c - 用于将指针转换为线性地址的 FP_SEG 和 FP_OFF 的替代方案

标签 c

在 16 位 dos 机器上,有 FP_SEG 和 FP_OFF 等选项用于将指针转换为线性地址,但由于这些方法在 32 位编译器上不再存在,还有什么其他函数可以在 32 位机器上执行相同的操作? >

最佳答案

幸运的是,不需要它们,因为 32 位模式是不分段的,因此地址始终是线性的(一种简化,但让我们保持简单)。

编辑:第一个版本令人困惑,让我们再试一次。

在 16 位分段模式下(我在这里专门指旧版 DOS 程序,其他 16 位 x86 操作系统可能类似)地址以由 16 位段组成的 32 位格式给出和一个 16 位偏移量。这些组合起来形成一个 20 位线性地址(这就是臭名昭著的 640K 屏障的来源,2**20 = 1MB 和 384K 为系统和 BIOS 保留,剩下约 640K 供用户程序使用)通过将段乘以 16 = 0x10 (相当于左移 4)并添加偏移量。即:线性 = 段*0x10 + 偏移量

这意味着2**12段:地址类型指针将引用同一个线性地址,因此一般情况下没有办法获得用于形成线性地址的32位值.

在使用远分段指针的旧 DOS 程序中(与近指针相反,近指针仅包含偏移量并隐式使用 ds 段寄存器),它们通常被视为 32 位无符号整数值,其中 16 个最高有效位是段,16 个最低有效位是偏移量。这给出了 FP_SEGFP_OFF 的以下宏定义(使用 stdint.h 中的类型):

#define FP_SEG(x) (uint16_t)((uint32_t)(x) >> 16) /* grab 16 most significant bits */ 
#define FP_OFF(x) (uint16_t)((uint32_t)(x)) /* grab 16 least significant bits */

要将 20 位线性地址转换为分段地址,您有多种选择 (2**12)。一种方法可能是:

#define LIN_SEG(x) (uint16_t)(((uint32_t)(x)&0xf0000)>>4)
#define LIN_OFF(x) (uint16_t)((uint32_t)(x))

最后一个简单的例子说明了它们是如何协同工作的:

分段地址:a = 0xA000:0x0123
作为 32 位远指针 b = 0xA0000123
20位线性地址:c = 0xA0123

FP_SEG(b) == 0xA000
FP_OFF(b) == 0x0123
LIN_SEG(c) = 0xA000
LIN_OFF(c) = 0x0123

关于c - 用于将指针转换为线性地址的 FP_SEG 和 FP_OFF 的替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7318958/

相关文章:

c - 初始化指向结构的指针数组

c - 特定计算机的软件堆栈

c - 寻找最接近的质数

c - 为什么 fork 我的进程导致文件被无限读取

c - 从文件中保存和获取数据

c - 如何获取变量的各个字节的值?

c++ - 计算立方体/长方体的边界框/缺失点

linux - 如何在 C 中获取 CPU 和内存使用情况? (在 Linux 系统中)

`scanf("%*s")` 会失败吗?

c - Fibodigits - 计算斐波那契数位