printf()函数的几个常见错误详解

本文深入探讨了使用printf函数时常见的错误,包括转化说明与参数不符和转换声明与待打印参数不对应的问题。举例说明了错误的printf调用如何导致输出错误,并解释了数据在计算机内存中的存储方式,以及转换说明如何影响数据的输出。最后提到了浮点数存储和参数传递的栈原理,以及数据截断的现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文适合有一定基础的新手,建议用于回忆复习,简单的知识点不再做解释。

错误示例:

float fnum;

fnum = 1.1;

printf("%d %d",2.2);

此处想要输出1.1和2.2,输出结果显然与期望不符。

1.转化说明(格式声明)与参数不符

此处的3.1是float型,转换说明却是%d。

在程序中,数据的存储方式是固定的,例如浮点型通常由32位组成,8位用于表示指数的值和符号,剩下的24位用于表示非指数部分,而int类型则是16位,1位表示正负号,其余表示整数的值。

当然C标准只规定了最小最大存储位数,因此此处只是举例,并不是任意系统的真实存储方式。

数据在电脑中的存储方式永远是0,1组成的有序数列,转换说明不会更改数据的存储方式,只是起到了翻译数据的作用,因此,当转换说明与数据的存储方式不同时,会输出错误的结果。

例如:

char a;

a = '65';

a是字符型,在电脑中以整数存储:1000001(注意:实际储存会经历由原码到反码再到补码的过程,但补码不便阅读,此处用的原码)

用%c,电脑会以字符型输出。

使用%i,电脑会先把二进制转换为十进制,再输出。

同理,对于整数若使用无符号的转换说明,电脑会将第一位识别位有效数字而非符号表达。

也正是因为如此,你不可能用转换字符去截断数据,例如不可能使用%2d去截断123,得到23,当最大字宽超过2,依旧会原样输出。此外,异常截断的说明会在文末。

值得注意的是,默认情况下,类似3.1这样未经声明直接使用的常数会被储存为double类,相较于float会拖累程序的运行速度,想要使用float保存,应当在浮点数后添加f。

例如:

2.1f*3.1f的计算速度会快于2.1*3.1

更改后依然错误的示例:

float fnum;

fnum = 1.1;

printf("%f %f",2.2f);

2.转换声明(格式声明)应与待打印参数一一对应。

更正后的示例:

float fnum;

fnum = 1.1;

printf("%f %f",fnum,2.2f);

常见的参数传递形式是通过栈来实现的,栈有以下特点,单进单出,先进后出。参数传递从栈顶开始,通过转换说明将储存的数据提取出来,但实际操作中,转换说明在栈底对齐,因此,即使靠后解释说明正确,也会受先前的转换说明的影响,造成栈中数据的解释错位。

截断

对于多位储存格式向少位存储格式转换会发生截断。

例如:

char a;

a = 1111;

printf("%c",a);

a的值明显溢出,但截断后的a不会是11,这是因为数据在电脑中以二进制储存。

对于截断后的数据,统一的计算方式为模以二的存储位长次方,例如char的存储为一字节八位,因此1111模以2的8次方为截断后的数据,同理int的存储为四字节三十二位,因此应模以2的多少次方呢?

答案是2的32次方,但数据超过2的31次方减1时会先占用符号位,此时数据已经异常了,符号位由零变1数据变负数。

例如:

2147483648结果为-2147483648

4294967297的结果为1

总之,理解了数据在电脑中的存储,转换和计算步骤,就能通过严谨的推导得到结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值