0

假设我有以下 C 代码

#include<stdio.h>

int main()
{
    float a=3.14;
    char j= a;
    printf("%d\n", j);
    return 0;
}

输出:3(如预期)

现在假设我使用指针做同样的事情。

#include<stdio.h>

int main()
{
    float a=3.14;
    char *j= (char*)&a;
    printf("%d\n", *j);
    return 0;
}

输出:-61

现在为什么我得到-61而不是3

编辑 从到目前为止的答案中,我了解到由于 char (通常)是 1 个字节长,所以 char 指针只选择第一个字节并给出-61而不是打印完整的浮点数。

但是,这里编译器如何确定数据类型的大小,以便它知道它必须在哪里停止打印。它是否由指针类型决定,因为它似乎通过答案到目前为止?

但理想情况下,在编译的词法阶段,创建符号表并且同时了解数据类型。

问题 所以,如果我使用 char 指针对编译器说,“嘿,伙计!只需打印您在我给出的 char 指针指向的位置找到的数据(类型)。”然后应该打印完整的浮点数因为编译器现在知道它是一个浮点数。?

4

6 回答 6

1
char *j= (char*)&a;

现在j指向 的第一个字节a,它本身可能有四个字节长。

printf("%d\n", *j);

在这里,您将 , 的底层表示中的第一个字节的值a作为 int 传递。

根据 IEEE 754,这是0x4048f5c3在此处查看)的第一个字节。假设你的机器是小端,你会得到0xc3. 您char已签名,因此您得到0x100-0xc3= 61


至于您的编辑:您不要求编译器打印指针指向的数据类型。编译器可以可靠地获得的关于此地址内容的唯一信息是它具有的静态类型,即 a char。C 中没有对类型信息的运行时支持。

编译器可能会意外地知道这个内存区域恰好是一个float(因为它很聪明和/或你给出了一个退化的例子),但这可能只有助于警告和优化;这个相同的案例怎么样?

void foo(char* j)
{
    printf("%d\n", *j);
}

// perhaps in a translation unit:

int main()
{
    float a=3.14;
    foo((char*)&a);
    return 0;
}

在这种情况下,您明确要求他将此内存区域视为一个字符,所以它就是这样做的,并且没有什么需要警告的。

于 2013-09-18T13:00:13.297 回答
0

因为您已经从正确的类型转换(您应该收到有关截断的警告)转变为按位转换的情况。当您只选择内存中表示的第一个字节而不进行某种语义转换时,所有的赌注都没有了。

于 2013-09-18T13:00:05.360 回答
0

这里是代码的描述:

#include<stdio.h>

int main()
{
    float a=3.14;

您声明一个a类型变量float并将 3.14 放入其中,根据浮点数的 IEEE754 表示,它是 0x4048f5c3。(http://www.binaryconvert.com/result_float.html?decimal=051046049052)所以基本上,在内存中,你有 4 个字节:0x4048f5c3

    char *j= (char*)&a;

您声明一个指向第一个字节的指针,该字节a包含 0xc3(取决于系统字节的内部表示)。由于j是 a char*,因此您忘记了所有其他字节。

    printf("%d\n", *j);

0xc3 是 -61 的签名字符(http://www.binaryconvert.com/result_signed_char.html?decimal=045054049

    return 0;
}

但是,在您编写的第一种情况下char j = a;a正确转换了 , 。

当然,如果你j输入 a float*,你可以访问完整的数字:

#include <stdio.h>

int main()
{
    float a=3.14;
    char *j= (char*)&a;
    printf("%d\n", *j);

    printf("%f\n", *((float*)j));

    return 0;
}

将打印:

-61
3.140000
于 2013-09-18T13:22:33.047 回答
0

第一个片段涉及将一种类型转换为另一种类型;当您分配3.14给时j,编译器会将值的表示形式从浮点格式(0xc3f54840在我的系统上)更改为char格式(0x03)。请记住,当浮点值转换为整数值时,小数部分会被截断。

在第二个片段中,您正在更改解释存储在a. 您正在传递一个指向第一个字节(值0xc3)值的指针。由于printf是一个可变参数函数,它将类型的值提升charint. 由于设置了 的高位0xc3,它会将值符号扩展为0xffffffc3,即 -65。

为了傻笑,我编写了以下代码来显示内存1中不同值的表示方式:

#include <stdio.h>

int main( void )
{
  float a  = 3.14;
  char  j  = a;
  unsigned char ju = a;
  char *jp = (char *) &a;
  unsigned char *jpu = (unsigned char *) &a;

  union { float a; unsigned char b[sizeof (float)]; } bytes;

  bytes.a = a;

  printf( "a    = %f\n", a );
  printf( "j    = %d\n", j );
  printf( "ju   = %u\n", ju );
  printf( "*jp  = %d (%02x) \n", (char) *jp, (char) *jp );
  printf( "*jpu = %u (%02x) \n", (unsigned char) *jpu, (unsigned char )*jpu );
  printf( "a representation  = " );
  for ( size_t i = 0; i < sizeof bytes.a; i++ )
  {
    printf( "%02x ", bytes.b[i] );
  }
  putchar( '\n' );
  printf( "j representation  = %02x\n", j );
  printf( "ju representation = %02x\n", ju );

  return 0;
}

这在我的系统上给出了以下结果:

a = 3.140000
j = 3
朱 = 3
*jp = -61 (ffffffc3)
*jpu = 195 (c3)
一个表示 = c3 f5 48 40
j 表示 = 03
菊代表= 03


1. 从技术上讲,我通过阅读与我上次分配的工会成员不同的工会成员来做出禁止;不记得这是否真的是未定义的行为。

于 2013-09-18T15:15:11.873 回答
0

您投射指针,但变量“a”中的引用数据仍然浮动。所以,打印不正确。您需要在打印前转换数据:

printf("%d\n", (int)(*(float*)(void*)j));
于 2013-09-18T13:01:54.970 回答
0

浮点变量的值应该使用浮点指令来解释,因为它使用一些浮点标准(如IEEE 754 )存储在内存中。

但是对char *的类型转换将使用一般整数指令来解释它,它不知道符号,所以结果是未定义的。

类型转换为char将导致使用浮点到整数的转换指令,结果将是浮点变量的尾数部分(除非它溢出目标变量大小)

于 2013-09-18T18:05:24.370 回答