程序员都知道,也都会使用printf函数,但你知道它也有“安全隐患”吗? ; L2 s* V( A4 C- t$ q
下面就来举例我说说:
/ m( p# y2 f# m2 e. ]
嵌入式专栏 1 问题描述打印输出的数据并不是理论值,如下图(右边):" r+ W" T s+ e U5 x! Q: \
% a! T# `% [: G# {
嵌入式专栏 2 进一步描述问题请细致注意看下面代码,有如以下奇怪的现象:
+ k9 V7 C( w5 n4 M# F- int a=5;
+ D" E/ m4 X: X - floatx=a; //这里转换是没有问题的。%f打印x是 5.000000: ^$ w& a; |# Q
- * a) q2 T% v; ~. c; ?1 ^: y4 l
- printf("%d\n",a);
. N! \. g4 R: @) m* B - printf("%f\n",a); //输出为什么是0.000000?-----问题19 G5 V( d( r4 w; o" D
- printf("%f\n",x);1 W$ J" J: E3 Q: @. T
- printf("%d\n",x); //输出为什么是0?-----问题26 {9 Y) |: a( P
- printf("%f,%f\n",a,x); //输出都是0.000000 为什么? ----问题3
- T5 T7 {2 A. a- E6 X2 R - printf("%f,%f\n",x,a); //调换一下a,x的顺序,正常了,为什么?----问题46 g) m2 a# t4 F
- printf("%d,%f\n",a,x);2 |4 \1 P/ e; Q: b2 z% `
; R! e3 v* q+ Z- getchar();. h6 U- \ c D/ f* I
- return0;
复制代码 . d: u! `* x4 Z
这里有四个问题,下面会进行解答。4 Q: k. L$ _# F3 U V2 ^ D
7 w! N; Y# g) Y9 c0 r& i a% _. \! n嵌入式专栏 3 printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。
8 U& {- f0 y6 o: J! {printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的:
2 U5 A6 F- n5 ^& L, S& Z
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。
+ l& W8 i J# y" G4 q比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。
. H) U% |% `, s( M3 `这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。 Y( R3 E/ x0 M( \- a
比如这种代码:
/ l: ~$ Y( t" k5 F- char string[]="Hello World!";$ o/ T6 Z& U( f P) @& w
- printf("String: %s ,强行再读一次: %#p\n", string);
9 S8 }; w S& j3 B0 }' Q - printf("String: %s ,强行再读一次: %#s\n", string);
复制代码
9 ?- u+ C& P# r输出如下:8 m4 H4 a2 K, x _6 T( e; }
; W b5 B5 G+ c4 b# l# M- ^- String:Hello World! , 强行再读一次: 0X001C1073
3 ?- n/ w- ^' R* \! T- Q - String: Hello World! ,强行再读一次: 閮
复制代码 & e! l5 h( w8 j0 ]
嵌入式专栏 4 问题解释问题1:printf("%f\n",a) 输出为什么是0.000000? 答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0
) T4 o% L6 D8 T+ ]7 L& j/ t问题2:printf("%d\n",x) 输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0
/ A, c! t) Z3 B6 a Q" I' m问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了, H0 X- q1 }$ ]" l) Q+ D% w
问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。
! d4 D9 j1 U- ^" i, C
$ p( p6 C0 o5 P' B0 W: m |