从printf说开去(二)

2024-01-03 01:18
文章标签 开去 printf

本文主要是介绍从printf说开去(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

     (接上回)

        我们在C/C++代码中使用:

            printf(“%f”, 10/3, 0×40080000 );

        看到运行结果了吗?为什么这行看起来不合乎所谓的语法的printf能输出3.000000呢?

        翻阅手册,回顾一下printf的格式化参数说明,你会发现%f的类型是double!
        我们知道在目前32位的机器上,sizeof(double) = 8字节 而sizeof(int) = 4字节,也就是说,机器在处理输出数据的时候,期望得到一个8字节的数据空间,而实际上只提供了一个4字节的数据空间,是不是这里出了问题?那么这个过程到底发生了些什么呢?

        10/3 这个数据由于是整数类型常数,他并不是在运行时进行计算的,而是在编译时,编译器把他翻译成了3。实质上,这段代码就与写printf(“%f”, 3)无异,他们完全等价。

        既然等价,为什么使用printf(“%f”, 3.0f);会输出正确的值?sizeof(3.0f) 不也等于4么?3.0f 和 整数3 是否等价?3.0和3.0f是否等价?

        似乎有点越扯越远,大家会不会有点糊涂了?要解释清楚这个过程确实需要一点口舌,不过别急,我们一个问题一个问题地说吧:


        问题一:printf(“%f”, 3.0f) 与 printf(“%f”, 3)的区别,3.0f和整数3在存储上有什么区别?3.0和3.0f在存储上有什么区别?

        其实,3.0f和整数3在内存中的表示是完全不同的,他们都占用4个字节空间,整数3在内存当中就是 0×00000003,而3.0f在内存中却为:0×40400000。

        并且,你会发现,3.0和3.0f在内存中的表示也不相同,3.0是一个双精度浮点数,他在内存中表示为:0×4008000000000000。你可以通过调试器查看这一点。
        那么浮点数是按什么规则表示的呢?IEEE标准从逻辑上用三元组{S,E,M}来表示浮点数N,其中S代表符号位,E代表指数位,M代表尾数。
        如果是单精度浮点数(float):N共32位,其中S占1位,E占8位,M占23位
        如果是双精度浮点数(double):N共64位,其中S占1位,E占11位,M占52位。

        (注:本文并不打算详细探讨浮点数的表示规则,有兴趣的朋友可自行参考IEEE754浮点数标准)
   
            N可以用以下公式算得:
            N = (-1)^S * m * 2^e

            当E的二进制位不全为0,也不全为1时,
            e = |E| – bias    (bias = 2^(k-1) – 1)
           单精度时k=8,bias=127 双精度时k=11,bias=1023

           其中m = |1.M|

           当E的二进制位全部为0时,此时:
            e = 1- bias
           m = |0.M|

 

           当E的二进制位全为1时,若M的二进制位全为0,则n表示无穷大,若S为1则表示负无穷,S为0则为正无穷。若M的二进制位不全为0时,表示NaN(Not a Number),代表着不合法或未初始化的值。

 

    例如:
    单精度浮点数3.0f,表示为2进制:
    S |            E         |                              M                                   |
    0  10000000  10000000000000000000000

    N = (-1)^0 * 1.5 * 2^1 = 3.0f

 

    双精度浮点数3.0,表示为2进制:
 符号位      指数位                                     尾数位
    S |                E              |                              M                                 |
    0  01000000000  1000 0000 0000 0000 … 0000

 

    看到了吗?他们的计算原理是一样的,但是位数不同,导致他们在内存里面的表示也不相同。


    3    在内存里面用16进制表示为:0×00000003
    3.0f 在内存里面用16进制表示为:0×40400000
    3.0  在内存里面用16进制表示为:0×4008000000000000

    我们现在知道了printf中%f是按double进行处理的,那么按双精度浮点规则,我们来看3是怎么被算成0的?


    3 用 64bit二进制表示:
    0000 0000 0000 0000 0000 0000 0000 … 0000 0011

    S |           E                    |                           M                                   |
    0  00000000000  0000 0000 0000 0000 … 0011


    这里的m已经是一个非常小,近乎于0的数字了,因此,在float保有的精度范围内,显示成为了0。


    有兴趣的同学可以算算,这个值大约等于:1.48乘以负的323次方。

 

    好,现在弄清楚了浮点数的表示,新的问题又来了,printf(“%f”, 10/3, 0×40080000 ); 能显示3.000000,这又是怎么工作的呢?

 

(未完待续)

这篇关于从printf说开去(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/564175

相关文章

printf sprintf fprintf

c语法 1.printf  .   sprintf   .   fprintf 1.1.printf 是把格式字符串输出到标准输出(一般是屏幕,可以重定向)。  1.2.sprintf sprintf,是把格式字符串输出到指定字符串中,所以参数比printf多一个char*。那就是目标字符串地址。 1.3fprintf fprintf, 是把格式字符串输出到指定文件设备中,所

printf打印带颜色的字体和背景

格式如下: printf("\033[字背景颜色;字体颜色m 字符串 \033[0m" ); 例子: printf("\033[1m\033[45;33m HELLO_WORLD \033[0m\n"); 颜色代码: QUOTE:  字背景颜色范围: 40--49                   字颜色: 30—39               40: 黑

printf笔记

1、控制打印颜色 1.1、通用格式: Esc[{attr1};{attr2};...;{attrn}m Esc为转义字符,值为:\033 {attr1}{attr2}{attrn}为属性,属性之间用分号相隔 红色前景输出: \033[31m 1.2、属性列表: 1.2.1、通用格式 0 重置所有属性 1 高亮/加粗 2 暗淡 4 下划线 5 闪烁 7 反转 8 隐藏

Printf 的格式输出探索

#include<stdio.h>int main() //%[flags][width][.prec][hlL]type{ printf("%9d\n",123);//数字输出占据9个字符空间,右对齐printf("%-9d\n",123);//左对齐printf("%+9d\n",123);//^^^^^+123printf("%+-9d\n",123);//+123printf("%-+

使用C标准库中的printf输出

1、增加文件系统调用 对系统调用进行了调整,一是将所有的系统调用实现转移 从头文件转移到C文件中; 二是增加几个有关文件打开和关闭的接口 主要是将系统调用做成单独的app库,这个库可以供其它所有的应用程序使用 2、导入newlib库,并调用 newlib可移植性强,具有可重入特性、功能完备等特点。Newlib的所有库函数都建立在20个桩函数的基础上[2],这20个桩函数完成一些ne

c printf 缓冲区分析

printf行缓冲区的分析总结 2013-08-18 12:29  5222人阅读  评论(7)  收藏  举报   分类: app program(9)  版权声明:本文为博主kerneler辛苦原创,未经允许不得转载。   最近在客户那调试串口的时候,read串口然后printf打印,单字符printf,发现没有输出,后来想起来printf这些

【STM32开发笔记】STM32H7S78-DK上的CoreMark移植和优化--兼记STM32上的printf重定向实现及常见问题解决

【STM32开发笔记】STM32H7S78-DK上的CoreMark移植和优化--兼记STM32上的printf重定向实现及常见问题解决 一、CoreMark简介二、创建CubeMX项目2.1 选择MCU2.2 配置CPU时钟2.3 配置串口功能2.4 配置LED引脚2.5 生成CMake项目 三、基础功能支持3.1 支持记录耗时3.2 支持printf输出到串口3.3 支持printf输出

IAR CC2530调试输出printf打印信息

1、很多网友给出的操作是:在General Options-> LibratyConfiguration下选择Smihoste 但是,我用的IAR8.10.3 (8.10.3.40338),根本无此选项,如下图: 2、采用另一种方式,在调试的过程中view->Terminal IO, 即可看到printf打印。

【STM32 HAL】多串口printf重定向

【STM32 HAL】多串口printf重定向 前言单串口printf重定向原理实现CubeMX配置Keil5配置 多串口printf重定向 前言 在近期项目中,作者需要 STM32 同时向上位机和手机发送数据,传统的 printf 重定向只能输出到一个串口。本文介绍如何实现 printf 同时输出到多个串口 单串口printf重定向 原理 为了使用 printf() 函

stm32的UART重定向printf()

1配置好uart 2打开usart.c文件 3在此文件前面添加头文件 4在末尾添加重定向代码 添加的代码 /* USER CODE BEGIN 1 *///加入以下代码,支持printf函数,而不需要选择use MicroLIB //#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #if 1//#pragma i