指针铸造

时间:2018-03-23 21:21:43

标签: c pointers

这段代码是什么意思?我的意思是,似乎我们取一个变量的地址并将其转换为(指针类型),之后我们将其引用,因为我们将知道该值。我错了吗?

#include "stdio.h"

int main(void) {

  int numI = 3;
  float numF = * (float *)&numI;

  printf("%f", numF); 

  numF = 3.0;
  numI = * (int*)&numF;

  printf("\n%d", numI); 

  return 0;
}

1 个答案:

答案 0 :(得分:2)

请考虑以下步骤:

  • numInumF是两个碰巧在您的架构上具有相同大小的对象,即4个字节。
  • &numI是类型为int *的表达式,其值为对象numI的地址。
  • 使用(float *)&numI投射它是float *类型的表达式,具有相同的值。为了告诉编译器,这个地址是float 的地址。
  • 取消引用此表达式*(float *)&numI会生成float类型的值,该值取决于值int的{​​{1}}的实际表示形式。例如,在intel核心处理器(小端,32位,2s补码)上,地址3的字节将包含intI03 00 00 00对象使用IEEE-756标准在同一处理器的内存中表示:float代表非常小值 1.5 x 2 -148 < / sup> ,大约 4.2039e-45
  • 将此值作为变量参数传递给03 00 00 00,首先将其转换为printf类型,具有相同的值,double将值转换为printf,因为格式为{{ 1}}仅指定6个小数位且没有指数。为了获得更精确的转化,您可以使用生成0.000000的{​​{1}}或生成十六进制表示%f的{​​{1}}。
  • 程序的第二部分执行相反的转换:将IEEE-756表示为%g的{​​{1}}值4.2039e-45重新解释为%a,生成值0x1.8p-148

以下是程序的修改版本,使其更加明确:

float

输出:

3.0F

但请注意:

  • 这些强制转换违反了严格的别名规则,因此具有未定义的行为。
  • 类型00 00 40 40int在内存中的表示是特定于体系结构的。一些系统表示具有大端字节顺序的1077936128,一些系统具有填充位和陷阱值,一些复古系统甚至使用一个补码或符号+幅度表示。尽管大多数当前系统使用与整数相同的字节排序的IEEE-756,但#include <assert.h> #include <math.h> #include <stdio.h> #include <string.h> int main(void) { int numI; float numF; unsigned char *p; assert(sizeof numI == sizeof numF); numI = 3; p = (unsigned char *)&numI; printf("int value %d is represented in memory as %02X %02X %02X %02X\n", numI, p[0], p[1], p[2], p[3]); //numF = *(float *)&numI; memcpy(&numF, &numI, sizeof numF); printf("reinterpreted as float with format %%f: %f\n", numF); printf("reinterpreted as float with format %%g: %g\n", numF); printf("reinterpreted as float with format %%a: %a\n", numF); printf("numF exact value: %g * 2^-148\n", numF * pow(2.0, 148)); numF = 3.0; p = (unsigned char *)&numF; printf("float value %.1g is represented in memory as %02X %02X %02X %02X\n", numF, p[0], p[1], p[2], p[3]); //numI = *(int *)&numF; memcpy(&numI, &numF, sizeof numI); printf("reinterpreted as int with format %%d: %d\n", numI); printf("reinterpreted as int with format %%#X: %#X\n", numI); return 0; } 的表示可能更具异国情调。因此,您的程序再次具有未定义的行为,并且最多会产生特定于实现的输出。
  • 重新解释内存中表示的推荐方法是使用int value 3 is represented in memory as 03 00 00 00 reinterpreted as float with format %f: 0.000000 reinterpreted as float with format %g: 4.2039e-45 reinterpreted as float with format %a: 0x1.8p-148 numF exact value: 1.5 * 2^-148 float value 3 is represented in memory as 00 00 40 40 reinterpreted as int with format %d: 1077936128 reinterpreted as int with format %#X: 0X40400000 复制字节,如修改后的代码所示。现代编译器将为此生成非常有效的代码,将int扩展到仅仅2条指令,如果不是更少。