RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1203434
Accepted
Danny
Danny
Asked:2021-11-12 05:59:34 +0000 UTC2021-11-12 05:59:34 +0000 UTC 2021-11-12 05:59:34 +0000 UTC

C 指针类型转换

  • 772

我有代码:

int a = 1065353216;
int* pa = &a;

printf("%d", *((float*)pa)); // Выводит 0

为什么输出为0?我理解sizeof(int*) == sizeof(float*),也就是考虑了4个字节的信息,但是这个信息的二进制表示被解释为整数,那么输出应该是1065353216,有什么问题?

PS二进制表示:

1065353216: 00111111 10000000 00000000 00000000(1.0 代表 IEEE754 代表浮点数)

c
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Zhihar
    2021-11-12T06:32:19Z2021-11-12T06:32:19Z

    本质上,您的代码执行以下操作:

    int a = 1065353216;
    int* pa = &a;
    
    float* pb = (float*)pa;
    
    float b = *pb;
    
    printf("%d", b);
    

    那些。您正在尝试执行以下操作:

    printf("%d", 1.0f);
    

    并且0仅因为您没有传递 int 而返回,即 这是一种指示错误的方法

    警告 C4477“printf”:格式字符串“%d”需要“int”类型的参数,但可变参数 1 具有“float”类型

    • 2
  2. AlexGlebe
    2021-11-12T18:08:53Z2021-11-12T18:08:53Z

    类型不匹配会导致未定义的行为。gcccprintf将类型转换float为double,然后打印。

    编码 :

    #include <stdio.h>
    int main(){
    int a = 1065353216;
    int* pa = &a;
    
    printf("%d\n", *((float*)pa)); // Выводит 0
    printf("%d\n", *pa);
    }
    

    汇编:

    .LC1:
            .string "%d\n"
    main:
            push    rax
            movsd   xmm0, QWORD PTR .LC0[rip] ; здесь float -> double
            mov     edi, OFFSET FLAT:.LC1
            mov     al, 1
            call    printf
            mov     esi, 1065353216 ; целые числа передаются через esi
            mov     edi, OFFSET FLAT:.LC1
            xor     eax, eax
            call    printf
            xor     eax, eax
            pop     rdx
            ret
    .LC0:
            .long   0
            .long   1072693248 ; тут float константа числа 
    

    结论 :

    -490767160
    1065353216
    

    关联 :

    https://godbolt.org/z/6on83T

    由于在第一个printf编译器没有将数字加载到寄存器esi中,因此将打印一个随机数。不同的编译器是不同的。

    • 2
  3. Best Answer
    wololo
    2021-11-12T20:44:46Z2021-11-12T20:44:46Z

    首先,您的程序的行为是未定义的,因为它违反了严格的别名。您不能像引用类型对象int一样引用类型对象float。

    其次,您的程序的行为是未定义的,因为printf传递给函数的参数与使用的转换说明符不匹配。该函数printf期望接收int并且您传递一个类型的参数double。

    第三,即使前两个 UB 按预期工作,您也不遵守默认参数Promotions 。type 参数float转换为 type double。所以在这一行中,printf("%d", *((float*)pa));函数printf实际上获取了类型的值,double并尝试输出 8 字节参数的前 4 个字节(假设类型int占用 4 个字节,类型double占用 8 个字节)。

    如果传递的类型值为double,1.0则 64 位浮点数的尾数的所有 52 位为零。这意味着前四个字节很可能也等于零(如果构成类型对象的字节 double以某种不寻常的顺序存储,则可能不等于零)。

    示例:

    #include <stdio.h>
    #include <inttypes.h>
    #include <string.h>
    
    int main(void)
    {
        float a = 1.0f;
        double b = a;
    
        uint32_t a32, b32;
        uint64_t b64;
    
        memcpy(&a32, &a, sizeof(a32));
        memcpy(&b64, &b, sizeof(b64));
        memcpy(&b32, &b, sizeof(b32));
    
        printf("a32 = %" PRIu32 "\n", a32);
        printf("b64 = %" PRIu64 "\n", b64);
        printf("b32 = %" PRIu32 "\n", b32);
        
        return 0;
    }
    

    结论:

    a32 = 1065353216
    b64 = 4607182418800017408
    b32 = 0
    

    因此,您的代码在解析时UB等效于以下内容:

    printf("0");
    
    • 1

相关问题

  • free 出于某种原因不会从内存中删除数组

  • 请帮助代码

  • 为什么 masm 对字符串或文本文字太长发誓,为什么在结构中设置 db 或 dw?

  • 如何将数字拆分为位并将其写入 C 中的数组?

  • 如何以给定的角度移动物体?

  • 解决“子集和问题”的时效算法

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5