繁体   English   中英

指针相等是否意味着整数相等?

[英]Does pointer equality imply integer equality?

对于int *a, int *b ,是否a == b暗示(intptr_t)a == (intptr_t)b 我知道在现代X86 CPU上也是如此,但C标准或POSIX或任何其他标准是否为此提供了保证?

C标准无法保证这一点。 (这个答案不涉及POSIX或其他标准是否说关于intptr_t 。)什么是C标准(2011,N1570草案)称, intptr_t是:

7.20.1.4 1以下类型指定一个带符号的整数类型,其属性是任何有效的void指针都可以转换为此类型,然后转换回指向void的指针,结果将等于原始指针: intptr_t

作为理论证明,一个反例是具有24位地址的系统,其中高8位未使用,但可用的整数类型是8位,16位和32位。 在这种情况下,C实现可以使intptr_t成为32位整数,并且它可以通过将24位地址复制到32位整数并忽略高8位来将指针转换为intptr_t 这些比特可能会遗留在之前的任何东西上。 intptr_t值转换回指针时,编译器会丢弃高8位,从而产生原始地址。 在这个系统中,当a == b被评估指针ab ,编译器通过仅比较地址的24位来实现这一点。 因此,如果ab指向同一对象a == b将为真,但是(intptr_t) a == (intptr_t) b可能因为忽略的高位而评估为假。 (注意,严格来说, ab应该指向void或者在转换为intptr_t之前应该转换为指向void指针。)

另一个例子是使用一些基址和偏移寻址的系统。 在该系统中,指针可能由指定某个基址的16位和指定偏移的16位组成。 基数可能是64字节的倍数,因此由baseoffset表示的实际地址是base •64 + offset 在这个系统中,如果指针a有基数2和偏移量10,它表示与指针b相同的地址,基数为1,偏移量为74.比较指针时,编译器会为每个指针计算基数 •64 + 偏移量并比较结果,所以a == b计算结果为true。 但是,当转换为intptr_t ,编译器可能只是复制这些位,从而为(intptr_t) a生成131,082(2•65536 + 10),为(intptr_t) b生成65,610(1•65536 + 74)。 然后(intptr_t) a == (intptr_t) b计算结果为false。 但是将intptr_t转换回指针类型的规则会使原始指针仍然成立,因为编译器只会再次复制这些位。

标准不是试图指定普通平台上的质量实施应该维护的所有保证,而是寻求避免强制任何可能在任何可能的平台上昂贵或有问题的保证,除非它们非常有价值以证明任何可能的成本。 作者预计(当时合理地)可以提供基本上没有成本的更强保证的平台的质量编译器会这样做,因此需要明确强制编译器要做的事情。

如果看一下标准提供的实际保证,这是荒谬的懦弱。 它指定将void *转换为uintptr_t然后再转换为void *将产生可与原始对象进行比较的指针,并且比较将报告两个指针相等。 它没有说明如果代码使用往返转换指针执行任何其他操作会发生什么。 一致的实现可以以忽略整数值的方式执行整数到指针的转换(除非它是空指针常量)并产生一些与任何有效或空指针不匹配的任意位模式,然后有它的指针只要操作数保持特殊位模式,-equality运算符就会报告“相等”。 当然,质量实施不应该以这种方式表现,但标准中的任何内容都不会禁止它。

在没有优化的情况下,假设在任何使用与uintptr_t大小相同的“线性”指针的平台上,质量编译器将处理指向uintptr_t转换,以便等指针的转换将产生相同的数字是合理的。价值,给定uintptr_t u; ,如果u==(uintptr)&someObject ,则*(typeOfObject*)u可用于访问someObject ,至少在someObject的地址转换为uintptr_t和下次someObject通过其他方式访问的时间之间,关于如何u来保值。 不幸的是,一些编译器过于原始,无法识别将地址转换为uintptr_t会表明由uintptr_t形成的指针可能能够识别同一个对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM