printf函数的类型转换问题
Posted 正义的伙伴啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
实际上整型与整型在打印时也就用到了两点:
- 整型提升——涉及两种类型的运算,两个值会分别转换成两种类型的更高级别
- 截断
整型与浮点型
#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的类型与打印的类型相符合,结果也是一堆乱码。
以上是关于printf函数的类型转换问题的主要内容,如果未能解决你的问题,请参考以下文章