我对 C 中的类型转换有疑问:
void *buffer;
(int *)((int)buffer);
这种类型的铸造在做什么?做什么((int)buffer)
?
想象一下,你在像我这样的 Linux/x86-64 计算机上。然后指针是 64 位并且int
是 32 位宽。
因此,buffer
变量已被初始化到某个位置;可能是 0x7fff4ec52020 (可能是某个局部变量的地址,可能是 inside main
)。
演员表(int)buffer
给你一个 int,可能是最低有效的 32 位,即 0x4ec52020
您再次使用 进行强制转换(int*)((int)buffer)
,这会为您提供虚假地址 0x000000004ec52020 ,该地址未指向有效内存。如果你取消引用那个虚假的指针,你很可能会得到一个 SIGSEGV。
所以在某些机器上(尤其是我的)(int *)((int)buffer)
与;不一样(int*)buffer
。
幸运的是,作为一个语句,(int *)((int)buffer);
它没有可见的副作用,并且会被编译器优化(通过“删除”它)(如果你要求它优化)。
所以这样的代码是一个巨大的错误(可能成为未定义的行为,例如,如果您取消引用该指针)。如果原始编码器真的想要这里描述的奇怪语义,他应该添加注释(这样的代码是不可移植的)!
也许#include
-ing<stdint.h>
和使用intptr_t
oruintptr_t
可能更有意义。
让我们看看 C 标准是怎么说的。在 C11 标准的最新免费发布版本http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf的第 55 页上,我们有
5 整数可以转换为任何指针类型。除非前面指定,结果是实现定义的,可能没有正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。
6 任何指针类型都可以转换为整数类型。除非前面指定,结果是实现定义的。如果结果不能以整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内。
这在您的示例中是什么意思?第 6 节说强制(int)buffer
转换会编译,但如果整数不足以容纳指针(这可能在 64 位机器上),结果是未定义的。final(int*)
转换为指针。
第 5 节说,如果整数大到足以容纳中间结果,则结果与从一开始就强制转换为 (int*) 完全相同。
简而言之,强制(int)
转换充其量是无用的,最坏的情况是导致指针值丢失。
在直接的 C 代码中,这是没有意义的,因为到和从的转换void*
是隐式的。以下将编译得很好
int* p = buffer;
更糟糕的是,这段代码可能会引入错误。考虑 64 位平台的情况。转换为int
会将指针截断为 32 位,然后将其分配给int*
. 这将导致指针值被截断并且肯定会导致错误。