将int转换为void指针并再次返回int是否安全?
在C和/或C ++中:将int转换为void指针并再次返回int是否安全?
基于问题“ C ++:将指针转换为int并稍后再返回指针是否安全? ”。
在大多数现代普通机器中,可能。
但是,我敢打赌,有一些模糊的编译器或配置(比如,一个使用32位整数运算的16位寻址机),但事实并非如此。
但是, uintptr_t保证同时包含两者,因此如果您愿意,请使用该类型。
下面是一个示例,在将整数转换为指针时,将指针转换为整数可能不会产生相同的指针。
给定一个具有24位地址并使用两个16位数量来描述位置的架构。 让一个数量为SEGMENT,另一个为OFFSET。 位置由符号SEGMENT:OFFSET指定。
实际的24位(物理)地址由以下公式计算:
address = segment * 16 + offset.
使用这种表示法,可以有多个描述相同物理地址的SEGMENT:OFFSET对。
转换为整数时,使用32位(无符号)数量(以简化处理器中的内部计算)。 问题是如何将物理地址转换为在创建物理地址时使用的相同SEGMENT :: OFFSET。
将整数转换为指针的通用公式为:
offset = address & 0xFFFF; // Mask off high order bits, keep lower 16. segment = address >> 16; // Shift address right 16 bits, zero fill.
虽然这个新段的物理地址和偏移量等于原始SEGMENT:OFFSET的物理地址,但不保证段和偏移量是相同的。
为了优化代码,有一些处理器指令在段中使用相对寻址。 当SEGMENT值因物理地址转换而发生变化时,这些指令可能会混乱。
在这种情况下,可以从指针转换为整数。 但是,从整数到指针的转换是非常难以辨别的。 在运行时可能会发生难以调试的错误。
奖金问题:你能说出实际的架构吗?
你为什么想做这个?
对C的回复,我对C ++的了解不够:不,没有定义行为将int
为void*
。 首先,如果你有这样的东西,你应该总是使用uintptr_t
。 使用int
是滥用。
然后,如果您的uintptr_t
不是来自有效地址,则C不保证任何内容。 它只能保证反过来。 不要这样做。
编辑:这是C99标准的相关部分。 正如您所看到的,所有警报都可以消失……
整数可以转换为任何指针类型。 除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示
最后一个特别令人尴尬,因为这意味着这样获得的指针值不能再被使用,直到它被覆盖:
某些对象表示不需要表示对象类型的值。 如果对象的存储值具有这样的表示,并且由不具有字符类型的左值表达式读取,则行为是未定义的。 ……这种表示称为陷阱表示 。
不可以。无效指针与任何其他指针的大小没有区别。 因此,它将遇到与其他指针类型完全相同类型的问题。
它的实现定义与最后一个问题一样,并且出于同样的原因。 它不太可能导致不良行为,但它仍然是实施定义的。
不会。在某些情况下,它似乎适用于某个编译器和设置,然后两年后,您花费数周时间调试某些内容发生了变化,转换不再按预期工作。
如果你只是以不需要这种行为的方式设计你的代码(最好的情况是避免使用这种转换,最坏的情况下使用char[]
)那么你将不必担心未来会出现模糊的错误。
不必要。 取决于指针的大小。 你为什么想做这个?
如果你的整数范围相当小,你总是可以这样做:
static const char dummy[MAXVAL];
然后使用dummy+i
作为将i
编码为指针的方式。 这是100%便携式。 如果您只关心它是99%便携式,您可以使用(char *)0 + i
。