printf输出之奇怪数据

研究问题

  1. printf输出时数据在内存中的读取顺序?

要点
  1. 赋值号有数据类型转换的作用;printf不带类型转换,且解析数据类型失败时打印0。
截图展示区
  1. Code1:
#include <stdio.h>
int main(void)
{
    float a = 2.5;
    int b = 2;
    printf("%d\n%f\n%d\n%f\n", a, a, b, b);    
    putchar('\n');
    printf("%f\n%d\n%f\n%d\n", a, a, b, b);    
    return(0);
}

分析:

32位编译器下:sizeof(int) 是 4, sizeof(double) 是 8

  (int)a_>|       |4byte
          |__2.5__|4
(float)a_>|       |4
  (int)b_>|__2.5__|4
          |___2___|4
(float)b_>|___2___|4

  第一个 %d 读到的实际是 2.5 的前 4 byte。 紧接着第一个 %f 读的是 2.5 的后 4 byte, 加上下一个 2.5 的前 4 byte. 同理,第二个 %d 读到的是 2.5 的后 4 byte, 而第二个 %f 读到的是两个 2。

  prinft依赖于vsprintf,而vsprintf的实现依赖这几个宏,它会根据格式字符串(也就是那些%d %f …)来调用va_arg,如果你的格式字符串和你后面的不定参数没有正确对应起来,那么也有可能在获取不定参数时出现错位。
还有float(32位)参数在传递printf的时候会自动转换成double(64位)(这也是%f和%lf没区别的缘故),int参数占32位。
注:以下连续的十六进制数据从左到右对应于内存地址的由低到高。

  你传入的参数a,a,b,b,对应十六进制的00 00 00 00 00 00 04 40 00 00 00 00 00 00 04 40 02 00 00 00 02 00 00 00正确的分割应该是:
a: [00 00 00 00 00 00 04 40]
a: [00 00 00 00 00 00 04 40]
b: [02 00 00 00]
b: [02 00 00 00]

  根据你的第一次输出的格式字符串,printf做了如下的分割:
%d: [00 00 00 00] int,对应0x00000000,也就是0了
%f: [00 00 04 40 00 00 00 00] double,0.0,(看double的表示法)
%d: [00 00 04 40] int,对应0x40040000,也就是10进制的1074003968
%f: [02 00 00 00 02 00 00 00] double,0.0
所以输出也就是:
0
0.000000
1074003968
0.000000
  而根据你第二次输出的格式字符串,printf做了如下的分割:
%f: [00 00 00 00 00 00 04 40] double, 对应2.5
%d: [00 00 00 00] int 对应0
%f: [00 00 04 40 02 00 00 00] double,对应0
%d:[02 00 00 00] int 对应0
也就是你看到的:
2.500000
0
0.000000
2

至于为什么好几次double都变成0.0,你需要去看看IEEE的double表示标准。

简而言之就是:printf的在做输出的时候会根据格式字符串来获取传递进来的不定参数,而错误的格式字符串会导致不定参数的获取错误,从而导致输出错误。

来自 https://segmentfault.com/q/1010000002534752

  1. Code2:
#include<stdio.h>
void main()
{
    printf("%d,%d\n",10.9,10);
    printf("%d\n", 10.9);
    printf("%d\n", 10);
    getchar();
}

分析:

栈一(第一行printf):
   (int)_>|       |4byte
   (int)_>|__10.9_|4
          |___10__|4

栈二(第二行printf):
   (int)_>|       |4
          |__10.9_|4

栈三(第三行printf):
   (int)_>|__10___|4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值