printf函数的类型转换问题

转换说明

printf是我们最常用的的一个c语言的库函数之一,printf打印数据的指令要与待打印数据的类型相匹配,例如打印整数时要用%d,打印字符要用%c。这些符号被称为转换说明
常见的转换说明:

%a浮点数、十六进制数和p计数法
%c单个字符
%d有符号十进制整数
%e浮点数,e计数法
%f浮点数、十进制计数法
%p指针
%s字符串
%o无符号八进制数
%u无符号十进制数
%x无符号十六进制数,使用十六进制数0f

转换说明修饰符

标记

例如:-、+、空格、#和0

在这里插入图片描述

数字

如果该字段不能容纳待打印的数字或字符串,系统回使用更宽的字段

.数字

精度

  • 对于%e、%E和%f转换,表示小数点右边数字的位数
  • 对于%s转换,表示待打印字符的最大数量
  • 对于整型转换,表示待打印数字的最小位数

h

和整型转换说明一起使用,表示short int和unsigned short int类型的值

hh

和整型转换说明一起使用,表示signed char和unsigned char类型的值

l

和整型转换说明一起使用,表示long int和unsigned long int类型的值

L

和浮点转换说明一起使用,表示long double 类型的值

代码示例:

#include<stdio.h>
int main()
{
	int a = 5;
	printf("%5d\n", a);
	printf("%.5d\n", a);
	printf("%05d\n", a);
	printf("%-5d\n", a);
	printf("%-05d\n", a);
	return 0;
}

运行结果:
在这里插入图片描述

转换说明的意义

转换说明把以二进制格式储存再计算机中的值转换成一系列字符(字符串)以便显示

转换很容易被人错误的理解为原始值换成转换后的值。实际上,转换说明时翻译说明,%的意思是“把给定的值翻译成十进制整数文本打印出来”,也就是把机器的语言翻译成目标值并打印出来,所以即使在某些情况下,转换不匹配,打印出来的值和转换符的类型相同,实际上转换符决定了打印出来的值。

转换不匹配

整型与整型

正常的认知都认为,转换说明应该与待打印值得类型相匹配。例如打印 int类型用%d %x %o,打印char 类型用%c、转换说明与待打印类型不匹配会怎么样?


#include<stdio.h>
int main()
#define pages 336
#define words 65618 //这里用define是因为define定义的变量类型是未知的,所以下面使用就不用声明相应类型的变量了
{
	short num = pages;        //0000 0001 0101 0000
	short mnum = -pages;      //1111 1110 1011 0000
	printf("num as short and unsigned short:%hd %hu\n",num,num);  //0000 0001 0101 0000
	printf("mnum as short and unsigned short:%hd %hu\n",mnum,mnum);  //1111 1110 1011 0000  
	printf("num as int and char %d %c\n", num, num);  //1111 1111 1111 1111 1111 1110 1011 0000 和 0101 0000=80 查ASCII码对照表可知结果
	printf("words as int ,short ,char:%d,%hd,%c", words, words, words);
	return 0;

}
//如果要用%d打印就要发生整型提升,二进制位会提升为32位,规则为有符号补符号位,无符号补零
//1111 1111 1111 1111 1111 1110 1011 0000
//1000 0000 0000 0000 0000 0001 0101 0000

//words
//%d 0000 0000 0000 0001 0000 0000 0101 0010 //转型提升
//%hd  0000 0000 0101 0010       // 截断
}

运行结果
在这里插入图片描述

如果对这块内存二进制码不太了解的可以参考这个——0.0
实际上整型与整型在打印时也就用到了两点:

  1. 整型提升——涉及两种类型的运算,两个值会分别转换成两种类型的更高级别
  2. 截断
整型与浮点型
#include<stdio.h>
int main()
{
	float n1 = 3.0;
	double n2=3.0;
	long n3 = 2000000000;
	long n4 = 1234567890;
	printf("%.le %.le %.le %.le\n", n1, n2, n3, n4);
	printf("%ld %ld \n", n3, n4);
	printf("%ld %ld %ld %ld\n",n1,n2,n3,n4);
	return 0;
}

代码结果:
在这里插入图片描述
打印第一行:n1和n2被正确的打印出来了,但是n3和n4就打印错误了,这是因为转换符%e告诉printf函数要以浮点型类型打印,但实际上传过去的时一个整型,浮点型有八个字节,而整型只有四个字节,所以整型后面的四个字节也会被读取,组成八个字节并强行把他解释为浮点型。
还有一点要注意给printf出传递参数时,c编译器会把float自动转换成double类型,所以n1会被强制扩展成八个字节
打印第二行:类型与传的值相匹配打印正确!

打印第三行:
如果我们想知道为什么会出现这种结果,就必须额了解函数的传参

printf("%ld %ld %ld %ld\n",n1,n2,n3,n4);

函数printf()在栈上开辟空间,并把n4,n3,n2,n1传入进去。n1和n2时double类型为八个字节,n3和n4是整型为四个字节,放入栈时开辟内存的大小与转换符类型无关,只与变量类型有关。然后转到printf函数,printf函数根据转换符读取数据,%ld说明printf()应该每次读取四个字节,并将其解释为long int类型。
当读取n1时由于一次只能读取四个字节,所以n1被拆开成两段,前四个字节被读取,并且别强行解释为long int类型,接下来%ld读取剩下的四个字节,也就是n1的后四个字节。
在这里插入图片描述
所以到最后即使n3,n4的类型与打印的类型相符合,结果也是一堆乱码。

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值