程序员都知道,也都会使用printf函数,但你知道它也有“安全隐患”吗? 5 r/ D- r9 m) Z y
下面就来举例我说说:
$ y4 ]- C- L3 y3 N! d8 b3 |5 v
嵌入式专栏 1 问题描述打印输出的数据并不是理论值,如下图(右边):
; W. j3 g5 B q0 c9 V# [+ y$ { , @8 q n- R2 E C' g: `
嵌入式专栏 2 进一步描述问题请细致注意看下面代码,有如以下奇怪的现象:
; N2 X3 P! z( |- int a=5;
& `+ F+ K% u. l% R" _ - floatx=a; //这里转换是没有问题的。%f打印x是 5.000000
7 H, } M9 Z/ v* d* b- m- B
9 U0 I# ]2 i1 h- V" H- printf("%d\n",a);0 E* ]* s- U& ~7 ]" p0 w% I
- printf("%f\n",a); //输出为什么是0.000000?-----问题1
; j7 T3 c z+ C8 |/ [8 a( a - printf("%f\n",x);
; m( }+ q9 L7 |6 @9 [ - printf("%d\n",x); //输出为什么是0?-----问题2
% z. ]- a+ p, _' w+ \. ^ - printf("%f,%f\n",a,x); //输出都是0.000000 为什么? ----问题3
$ Q1 L" z4 a6 o/ V6 n+ h0 l; m5 | - printf("%f,%f\n",x,a); //调换一下a,x的顺序,正常了,为什么?----问题4/ ^! i" H# [6 B! s" V2 ]
- printf("%d,%f\n",a,x);
9 a! q/ h/ \6 s: U% t6 ] - 4 A$ |: k- g3 ]3 [9 U7 [8 i
- getchar();
5 z: Q) }" [+ z% w" f& ~ - return0;
复制代码
, e1 w; A% ` B; {8 V2 p" H这里有四个问题,下面会进行解答。
9 y7 ~8 `7 P7 [1 c$ a; P' P( P' V9 n
嵌入式专栏 3 printf()函数的原理解释明确这些问题首先须要明确printf()函数的工作原理。; ^! l+ M2 N& h3 G
printf()维持了一个需要打印的变量栈,默认情况下,參数进栈的顺序是由右向左的。因此,參数进栈以后的内存模型例如以下图所看到的:
5 j6 h& M* k* _1 z
打印的时候,printf依照字符转换说明符规定的格式从低地址開始提取数据。直到參数打印完。
$ v& ^5 ~0 A& K比方遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。printf()事实上不知道參数的个数,它仅仅会依据format中的打印格式的数目依次打印堆栈中參数format后面地址的内容。7 f/ ?8 `" Q w# _' D/ h6 Q$ g
这样一来,printf()事实上存在安全隐患:它会强行读取内存的数据当作正常数据输出,没有边界检测(非常有可能产生堆溢出)。
. G5 v& c4 h) @1 Y9 p( c1 _比如这种代码:
" {# l8 z- X- n" O! f: _9 o- char string[]="Hello World!";
: _" K5 I \- s& u3 A - printf("String: %s ,强行再读一次: %#p\n", string);7 Y& u1 S$ K G( z3 @
- printf("String: %s ,强行再读一次: %#s\n", string);
复制代码
: ~: D/ T" f8 K+ Q: d0 ^8 {输出如下:6 i. Q# j$ b3 s. a; v" ^
0 Y. d: @$ \- T5 C; Q, l- String:Hello World! , 强行再读一次: 0X001C1073
' }4 O+ K' A' {0 u) v# a" x u - String: Hello World! ,强行再读一次: 閮
复制代码 , j- F! z: o/ Q
嵌入式专栏 4 问题解释问题1:printf("%f\n",a) 输出为什么是0.000000? 答:%f 提取8字节。a仅仅有4字节,提取出来的数占了float表示法的指数部分。尾数部分为0。所以终于是0: f% w3 a' M8 N+ u, U/ ]! |( l$ S
问题2:printf("%d\n",x) 输出为什么是0?答:%d 提取4字节,x有8字节。提取出来的数实际上是float表示法的指数部分(恰好是0),所以终于是0# i. d( c( g% Q# T. h8 b
问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?答:參照问题1的解释。提取了八字节后,后面的已经乱了
5 ~1 {+ m0 G( b5 q问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?答:这是正常的情况而已。
6 l) G. k1 x f$ a# a1 b. C k$ d% b9 d N9 P
|