跳转至

C&C++数据类型二进制表示


1 浮点数

1.1 0.1+0.2!=0.3

1
2
3
4
5
6
7
#include<stdio.h>

int main()
{
    printf("%.17f\n",0.1+0.2);
    return 0;
}

输出结果为0.30000000000000004

由IEEE 754的原理造成,其他语言如Java、Python、C#也会出现这个问题

具体原理参见Python数据类型二进制表示

1.2 %d​输出浮点数变成 0

1.2.1 类型转换

摘自CSDN。原文链接:https://blog.csdn.net/weixin_45031801/article/details/142147962

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换 和 显式类型转换

隐式类型转化(截断或提升):编译器在编译阶段自动进行,能转就转,不能转就编译失败
显式类型转化(强转):需要用户自己处理
🥝隐式类型转换
隐式类型转换虽然简化了编程过程,但由于是编译器自动执行的,它会在某些情况下带来不可预期的问题,主要体现在以下方面:

隐式转换可能导致数据丢失:在隐式类型转换中,可能会将一个较大范围的数据类型转换为一个较小范围的类型,导致数据丢失或精度损失。例如,double 转换为 int,会丢失小数部分。

1
2
3
4
5
6
7
8
#include <stdio.h>

int main() {
    double pi = 3.14159;
    int truncatedPi = pi;  // 隐式转换,丢失小数部分
    printf("Truncated Pi: %d\n", truncatedPi);  // 输出:3
    return 0;
}

🍉显示类型转换
显式类型转换可以给程序员更多的控制权,但也可能引发一些问题,尤其是在不恰当地使用时。

不安全的转换:显式转换可以绕过编译器的类型检查,允许将完全不相关的类型相互转换。例如,将指针转换为整数类型,或将不同类型的指针相互转换,可能导致严重的运行时错误或未定义行为。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <stdio.h>
#include <stdint.h>  // 包含 uintptr_t

int main() {
    int a = 100;
    int *ptr = &a;

    // 使用 uintptr_t 来存储指针的整数值
    uintptr_t address = (uintptr_t)ptr;

    // 将整数转换回指针
    int *newPtr = (int*)address;
    printf("Dereferenced value: %d\n", *newPtr); // 100

    return 0;
}

最终我大概获得一个结论:

  1. 浮点数通过 %d 格式化输出会直接在二进制形式下裁剪至对应类型大小
  2. 如 20.0,二进制存储下后面小数部分全是 0,%d输出自然也为 0(参照[[Python数据类型二进制表示]])
  3. 浮点数通过 (int) 强制格式化输出能够将浮点数舍弃小数部分而转换