为什么会有人在C中使用这种类型的强制转换?浮点的引用被强制转换为int指针,然后被取消引用

为什么会有人在C中使用这种类型的强制转换?浮点的引用被强制转换为int指针,然后被取消引用,c,pointers,casting,C,Pointers,Casting,我在读Carmack的快速平方根逆算法时注意到: float x; // ... // int i = *(int*)&x; 为什么会有人选择使用这种奇怪的类型的铸造,而不仅仅是以下 int i = (int)x; 那不一样 inti=(int)x将把浮点转换为int,这将简单地截断它 inti=*(int*)&x将加载到i中当前存储在x中的相同位。结果是完全不同于截断x它被称为。它将把float解释为int。也就是说,位表示是完全复制的 这是一个潜在的危险操作,因为浮点整数的某些位

我在读Carmack的快速平方根逆算法时注意到:

float x;
// ... //
int i = *(int*)&x;
为什么会有人选择使用这种奇怪的类型的铸造,而不仅仅是以下

int i = (int)x;
那不一样

inti=(int)x
将把
浮点
转换为
int
,这将简单地截断它

inti=*(int*)&x
将加载到
i
中当前存储在
x
中的相同位。结果是完全不同于截断
x

它被称为。它将把
float
解释为
int
。也就是说,位表示是完全复制的

这是一个潜在的危险操作,因为浮点整数的某些位表示可能是作为整数的陷阱表示(但IEEE-754浮点和2s补码整数的情况并非如此)

此外,它可能不再工作,因为根据C标准,它的行为尚未定义。它违反了严格的别名规则

C仅支持通过
memcpy
访问不同类型的变量

这是编写操作的有效标准C方式:

int y; float x = 42.0f;
memcpy(&y, &x, sizeof(x));
C99增加了另一种方法,即使用
联合体

union { int y; float x; } u = { .x = 42.0f };
int y = u.y;

卡马克实际上并没有写算法;请看。为什么要选择第二个选项?我能想到的唯一原因是他们想直接操纵浮点的位表示。这就是我的想法。是的,这就是想法。我很好奇,因为这似乎是一个非常无用的想法,除非你已经知道特征/尾数浮点格式,但解释了这一点。操纵浮点的位表示,就像它是一个int一样,是算法背后的全部想法。它以一种巧妙的方式利用位格式进行计算。一个小细节:
(int)x
将被截断,而不是舍入。并集不是也违反了严格的别名吗?@Random832取决于您使用的C标准。从C99开始,它就不再是违规行为了。因为大多数编译器以前也允许这样做,所以该标准正式发布。我很好奇这两种方法(类型双关与联合)之间是否有性能差异。@Dai都是类型双关。它们只是实现它的不同方式。如果它们在性能方面不同,则取决于编译器,但是一个聪明的优化编译器可能会将两者转换为完全相同的程序集(clang和gcc都会这样做)。示例:@Random832,不,联合的东西肯定不会违反严格的别名。这是明确允许的。