简体   繁体   English

指针转换

[英]Pointer casting

What this code mean? 该代码是什么意思? i mean it's seem that we take the address of a variable and cast it to a (pointer type), after that we deferencing it, as we will know the value. 我的意思是,似乎我们采用了变量的地址并将其转换为(指针类型),之后我们对它进行了延迟,因为我们将知道该值。 Am I wrong? 我错了吗?

#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;
}

Consider these steps: 请考虑以下步骤:

  • numI and numF are 2 objects that happen to have the same size on your architecture, namely 4 bytes. numInumF是2个对象,它们在您的体系结构上恰好具有相同的大小,即4个字节。
  • &numI is an expression with type int * and its value is the address of the object numI . &numI是类型为int *的表达式,其值是对象numI的地址。
  • Casting it with (float *)&numI is an expression of type float * with the same value. 使用(float *)&numI是具有相同值的float *类型的表达式。 Aking to telling the compiler, this address is that of a float . 为了告诉编译器, 该地址是float地址
  • Dereferencing this expression *(float *)&numI produces a value of type float that depends on the actual representation of int for the value 3 . *(float *)&numI引用此表达式*(float *)&numI会生成一个float类型的值,该值取决于值3int实际表示形式。 For example, on the intel core processors (little endian, 32-bit, 2s complement) the bytes at address intI would contain 03 00 00 00 . 例如,在Intel核心处理器(小端,32位,2s补码)上,地址intI处的字节将包含03 00 00 00 float objects are represented in memory on the same processor using the IEEE-756 Standard: 03 00 00 00 represents the very small value 1.5 x 2 -148 , approximately 4.2039e-45 . float对象使用IEEE-756标准在同一处理器上的内存中表示: 03 00 00 00表示非常小的值1.5 x 2 -148 ,大约为4.2039e-45
  • Passing this value as variable argument to printf first converts it to type double , with the same value and printf converts the value to 0.000000 because the format %f specifies only 6 decimal places and no exponent. 将此值作为变量参数传递给printf首先将其转换为double ,并使用相同的值,而printf将该值转换为0.000000因为格式%f仅指定了6个小数位,并且没有指数。 In order to get a more precise conversion, you could use %g which would produce 4.2039e-45 , or %a which would produce the hexadecimal representation 0x1.8p-148 . 为了获得更精确的转换,可以使用%g生成4.2039e-45%a生成十六进制表示形式0x1.8p-148
  • The second part of the program performs the opposite conversion: the float value 3.0F whose IEEE-756 representation is 00 00 40 40 is reinterpreted as an int , producing the value 1077936128 . 程序的第二部分执行相反的转换:将IEEE-756表示为00 00 40 40float3.0F重新解释为int ,产生值1077936128

Here is a modified version of your program that makes it more explicit: 这是您的程序的修改后的版本,可以使它更加明确:

#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;
}

Output: 输出:

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

Note however that: 但是请注意:

  • These casts violate the strict aliasing rule, hence have undefined behavior. 这些强制转换违反严格的别名规则,因此具有未定义的行为。
  • The representation in memory of types int and float are architecture specific. intfloat类型的内存表示形式是体系结构特定的。 Some systems represent int with big-endian byte order, some have padding bits and trap values, some vintage systems even used one's complement or sign+magnitude representations. 一些系统以大端字节序来表示int ,一些系统具有填充位和陷阱值,一些老式系统甚至使用补码或正负号表示。 The representations for float can be even more exotic, although most current systems use IEEE-756 with the same byte ordering as integers. 尽管大多数当前系统使用的IEEE-756具有与整数相同的字节顺序,但float的表示形式可能更为奇特。 So your program has undefined behavior again, and at best produces implementation specific output. 因此,您的程序再次具有未定义的行为,并且充其量只能产生特定于实现的输出。
  • The recommended method for reinterpreting the representation in memory is to copy the bytes with memcpy , as shown in the modified code. 建议重新解释内存中的表示形式的方法是使用memcpy复制字节,如修改后的代码所示。 Modern compilers will produce very efficient code for this, expanding the memcpy to a mere 2 instructions if not less. 现代编译器将为此生成非常有效的代码,将memcpy扩展为仅2条指令(如果不是更少的话)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM