指针是数字吗?

指针与数字

前一节有过关于整数和浮点数及其表示的讨论。如果你还未读过,你起码现在应浏览一下,并应特别注意多种可能的整数表示和IEEE浮点数表示。

所有C指针总是具有一个,我们将在下一节提到的类型。在一个足够低的机器层次,大多数系统都有一些底层硬件指针类型:有时少至两个(一个用于数据以及一个用于代码),或甚至只有一个。然而在C中,每个指针值至少与其所指对象的类型关联。机器允许(但自然不是必要的)使用不同下层表示和/或内存字节数,生成每种不同指针类型。这令问题至少在概念上变得更复杂,但是我们仍会对每个不同的指针类型,问这个问题一次:一个现在存储在这个对象中的,对一些T类型来说,具有‘到T的指针’类型的值只是一个数字吗,或者它是一些更复杂的东西?

在C语言里面,一个有效的指针根本上带给你两个不同的信息:它所指向的对象的类型和该对象的位置。再那种意义上说,单是类型就令它是‘一些更复杂的东西’。但是让我们假装这不是问题。像我们会在后续介绍表达式时说的,任何对象均可被分解为字节。我们能用这个技巧,把一个指针值存储在一个具有正确类型的变量(或说一个对象)里,然后把那个对象分解为字节。这允许我们察看任何指针值的真实表示。

从这种意义上说,指针是数字:一个指针值,一旦存储于内存,便有一些底层的位模式。这种位模式能被解释为某些种类的整数。但是这就是事情变得微妙的地方:那仅为一种解释,而不是被使用的解释。

例如,假设在某个机器上那个指针恰巧是32位长,机器是8位字节并且是小端字节顺序。我们能填充一个指针值到内存中,然后提取四字节并得到一个32位整数:

    int *ip = malloc(20 * sizeof *ip);
    unsigned char *ucp;
    unsigned long l;

    if (ip == NULL)    panic("out of memory");
    ucp = (unsigned char *)&ip;
    l = ucp[0];
    l |= (unsigned long)ucp[1] << 8;
    l |= (unsigned long)ucp[2] << 16;
    l |= (unsigned long)ucp[3] << 24;
    printf("ip = %p; as an integer, %lu\n", (void *)ip, l);

这段代码向你展示存储于ip的32位指针的整数值。但这是ip的真实值吗,或仅是一些解释?如果组成指针的位确实是一个32位IEEE单精度浮点数会怎样?在这种情形,为了找到真实的值,我们必须考虑符号,尾数和指数的位。一个我们打印出的值(比如)1081081856打印为3.75可能更正确。

当然在这种特别的机器上,它可能真的是1081081856或者0x40700000。但是如果指针值实际上是结构化、类似(但可能不是同样的方式)浮点数值会怎样?

特别地,假定这种机器有可映射的‘段’,并且指针由一个12位段号码加上20位段内偏移量组成。这种情形,在这种机器中段号码为0x407,偏移量为0。把这两个放在一起,我们得到32位数字0x40700000。这里就是事情暗地里发生的地方。

在这个机器上,每个段可被标记为无效。如果我们调用free(ip),底层系统将标记段0x407无效。一个对这个指针值的尝试使用将被捕获(因为这个机器,不像其它大多数,确实被设计为捕获错误,而不是尽可能快地产生一个错误答案)。但现在段0x407无效,这个指针的值是什么呢?如果我们让C编译器直接打印它,这可能将它载入机器上的一个指针寄存器,并且可能会查找段号,注意它是无效的,并在运行时捕获。

    free(ip);
    printf("ip = %p\n", (void *)ip);

输出永不会产生,因为载入值并送至printf的尝试被捕获。一个随后的malloc()调用可能会令段0x407再次有效,但是关联它到RAM的不同部分,所以同一个指针(0x40700000)现在指向不同内存。

换言之,在这个机器上存储于指针的表示——内存位模式——永不改变。改变的是表示的值。值至少被部分建立,通过在一个单独的表中查找其(一部分)表示。不论何时只要表改变,存储在指针中的值也会。

今天的大多数机器不会做这些事情[1]。它在老式机器上较多见。然而C语言允许这样做,所以如果你要编写严格的可移植程序——保证你的代码能在将来的机器上运行——你用该避免察看无效指针值。它们可能并非表示你所期望的,在某些情形,这个值本身甚至不存在。


1.嗯,尽管并非显而易见:分页技术做所有这些事情,却对普通程序员隐藏了这一切。


(This Chinese translation isn't confirmed by the author, and it isn't for profits.)

Translator : jhlicc@gmai1.c0m
Origin : http://www.torek.net/torek/c/numbers2.html