下表列出了printf和scanf对于各种格式说明符可以接受的参数类型。
格式 | printf | scanf |
%c | int | char * |
%d, %i | int | int * |
%o, %u, %x | unsigned int | unsigned int * |
格式 | printf | scanf |
%ld, %li | long int | long int * |
%lo, %lu, %lx | unsinged long int | unsigned long int * |
%hd, %hi | int | short int * |
%ho, %hu, %hx | unsigned int | unsigned short int * |
%e, %f, %g | double | float * |
%le, %lf, %lg | n/a | double * |
%s | char * | char * |
%[...] | n/a | char * |
%p | void | void ** |
%n | int * | int * |
%% | none | none |
(严格地讲,%lf在printf下是未定义的,但是很多系统可能会接受它。要确保可移植性,就要坚持使用%f。)
最近在优快云上看到一个网友写下了类似如下代码,想以小数格式输出一个整数:
int
a
=
0
, b
=
0
;
printf( " %f, %d " , a, b);
printf( " %f, %d " , a, b);
因为我最近刚阅读了浮点数的内存表示方法,所以对上述代码做出解释如下:
%f为double类型,需要两个字节表示,所以,printf在遇到%f时即将a,b的两个整型数据都读了去,而到了需要输出%d的时候,只能读取b的下一个单元,自然不是所期望的数据了。
但是有朋友说%f是float类型,%lf才是double类型,具此我特意查阅了MSDN和Linux man手册,均没有发现此类描述,在linux man手册中,说明%lf为long double类型。
为了说明问题,我又做了几个实验:
实验一,检查%f需要读取几个字节
int
a
=
0
, b
=
0
, c
=
5
;
printf( " %f,%d\n " , a, b, c);
printf( " %f,%d\n " , a, b, c);
0,5
结论:%f读取8个字节,即两个整型大小
实验二,检查%lf需要读取几个字节
int
a
=
0
, b
=
0
, c
=
5
;
printf( " %lf,%d\n " , a, b, c);
printf( " %lf,%d\n " , a, b, c);
0,5
结论:%lf也读取8个字节(也许和机器位宽有关,我是32位的机器)
实验三,检查printf读取float类型数据
float
a
=
0.0f
;
int b = 5 ;
printf( " %f,%d\n " , a, b);
int b = 5 ;
printf( " %f,%d\n " , a, b);
0.0,5
结论:float类型只占4个字节的数据,但前面实验一已经证明%f会读8个字节,即double类型的宽度,所以,编译器在将float类型参数入栈的时候,事先转换成了double类型。
实验四,再次证明实验三的结论
float
a
=
0.0f
;
int b = 5 ;
printf( " %d,%d,%d\n " , a, b);
int b = 5 ;
printf( " %d,%d,%d\n " , a, b);
0,0,5
结论:a在入栈的时候,占了8个字节。
以上4步,我觉得可以证明 %f是按double类型输出的了 ,另外,我也知道了float类型在作为参数进行传递的时候,编译器会先将它转换成double类型。
转自http://www.cnblogs.com/Xiao_bird/archive/2010/03/26/1696908.html