博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C语言printf()函数具体解释和安全隐患
阅读量:2044 次
发布时间:2019-04-28

本文共 1528 字,大约阅读时间需要 5 分钟。

关注+星标公众,不错过精彩内容

编排 | strongerHuang

微信公众号 | 嵌入式专栏

程序员都知道,也都会使用printf函数,但你知道它也有“安全隐患”吗?

下面就来举例我说说:

嵌入式专栏

1

问题描述

打印输出的数据并不是理论值,如下图(右边):

嵌入式专栏

2

进一步描述问题

请细致注意看下面代码,有如以下奇怪的现象:

int a=5;floatx=a;     //这里转换是没有问题的。%f打印x是 5.000000printf("%d\n",a);printf("%f\n",a);  //输出为什么是0.000000?-----问题1printf("%f\n",x);printf("%d\n",x);  //输出为什么是0?-----问题2printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?   ----问题3printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?----问题4printf("%d,%f\n",a,x);getchar();return0;

这里有四个问题,下面会进行解答。

嵌入式专栏

3

printf()函数的原理解释

明确这些问题首先须要明确printf()函数的工作原理。

printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的:

打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。

比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。

这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。

比如这种代码:

char string[]="Hello World!";printf("String: %s  ,强行再读一次: %#p\n", string);printf("String: %s  ,强行再读一次: %#s\n", string);

输出如下:

String:Hello World!  , 强行再读一次: 0X001C1073 String: Hello World!  ,强行再读一次: 閮

嵌入式专栏

4

问题解释

问题1:printf("%f\n",a) 输出为什么是0.000000?

答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0

问题2:printf("%d\n",x)  输出为什么是0?

答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0

问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?

答:參照问题1的解释。提取了八字节后,后面的已经乱了

问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?

答:这是正常的情况而已。

免责声明:本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。

------------ END ------------

后台回复『嵌入式C语言』阅读更多相关文章。

关注微信公众号『嵌入式专栏』,底部菜单查看更多内容,回复“加群”按规则加入技术交流群。

点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

转载地址:http://dkxof.baihongyu.com/

你可能感兴趣的文章
SBTree的概念以及代码实现
查看>>
(PAT)Insertion or Heap Sort(堆排序与插入排序)
查看>>
(PAT 1002) A+B for Polynomials(利用双指针和归并排序思想)
查看>>
(PAT 1056) Mice and Rice (队列+模拟)
查看>>
最大公因数和最小公倍数
查看>>
静态链表及应用
查看>>
(PAT 1052) Linked List Sorting (链表)
查看>>
(PAT 1097) Deduplication on a Linked List (链表)
查看>>
(PAT 1103) Integer Factorization (深度优先遍历解决背包问题)
查看>>
(PAT 1091) Acute Stroke (三维广度优先遍历)
查看>>
(PAT 1076) Forwards on Weibo (图的广度优先遍历,控制遍历层数)
查看>>
(模板)已知二叉树先序(后序)中序,求这棵二叉树
查看>>
(PAT 1020) Tree Traversals (给出后序中序求二叉树层序)
查看>>
(PAT 1086) Tree Traversals Again (两种做法:模拟前序遍历和已知前序中序求树)
查看>>
(PAT 1102) Invert a Binary Tree(反转二叉树+寻找二叉树的根结点)
查看>>
(PAT 1015) Reversible Primes (进制转换+判断素数)
查看>>
(PAT 1110) Complete Binary Tree (判断完全二叉树)
查看>>
(PAT 1105) Spiral Matrix (WQNMD坑爹模拟题系列)
查看>>
(PAT 1021) Deepest Root (广度优先遍历求层数)
查看>>
(PAT 1134) Vertex Cover (图中边和顶点的关系)
查看>>