将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 ++的了解不够:不,没有定义行为将intvoid* 。 首先,如果你有这样的东西,你应该总是使用uintptr_t 。 使用int是滥用。

然后,如果您的uintptr_t不是来自有效地址,则C不保证任何内容。 它只能保证反过来。 不要这样做。

编辑:这是C99标准的相关部分。 正如您所看到的,所有警报都可以消失……

整数可以转换为任何指针类型。 除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示

最后一个特别令人尴尬,因为这意味着这样获得的指针值不能再被使用,直到它被覆盖:

某些对象表示不需要表示对象类型的值。 如果对象的存储值具有这样的表示,并且由不具有字符类型的左值表达式读取,则行为是未定义的。 ……这种表示称为陷阱表示

不可以。无效指针与任何其他指针的大小没有区别。 因此,它将遇到与其他指针类型完全相同类型的问题。

它的实现定义与最后一个问题一样,并且出于同样的原因。 它不太可能导致不良行为,但它仍然是实施定义的。

不会。在某些情况下,它似乎适用于某个编译器和设置,然后两年后,您花费数周时间调试某些内容发生了变化,转换不再按预期工作。

如果你只是以不需要这种行为的方式设计你的代码(最好的情况是避免使用这种转换,最坏的情况下使用char[] )那么你将不必担心未来会出现模糊的错误。

不必要。 取决于指针的大小。 你为什么想做这个?

如果你的整数范围相当小,你总是可以这样做:

 static const char dummy[MAXVAL]; 

然后使用dummy+i作为将i编码为指针的方式。 这是100%便携式。 如果您只关心它是99%便携式,您可以使用(char *)0 + i