首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

关于printf的有关问题,哪位高手能用printf的实现来解释一下

2012-02-16 
关于printf的问题,谁能用printf的实现来解释一下代码执行起来intmain(){inta1floatb1.0floatca/10//

关于printf的问题,谁能用printf的实现来解释一下
代码执行起来  
int   main()
{

                    int   a   =1;
                    float   b   =   1.0;
                    float   c   =   a/10;
                    //问题一:为什么不一样啊,   用%d输出b不是一次类型转换?

                    printf( "%d       \n ",   (int)(b));
                    printf( "%d       \n "     ,       b     );
                   
                    //这个更奇怪了,为什么,只是把第一个%d该成%f,后面的也会发生变化?                    
                    printf( "%d   ,   %f   ,   %f   \n ",   a/10   ,   b/10,   c   );
                    printf( "%f   ,   %f   ,   %f   \n ",   a/10   ,   b/10,   c   );
                   
                   

                    getch();
                    return   0;      
 
         
}

会得到这样的结果:
1
0
0   ,   0.100000   ,   0.000000
-0.000000   ,   0.000000   ,   -1.#QNAN0


小弟实在不解,望各位高人给点指教,谢谢了!


[解决办法]
printf 函数不会对参数进行类型检查, 也就不会转换
[解决办法]
int DEFUN(printf, (format), CONST char *format DOTS)
{
va_list arg;
int done;

va_start(arg, format);
done = vprintf(format, arg);
va_end(arg);

return done;
}

可以看到printf其实在内部调用的是vprintf,通过查看vprintf.c中的内容,我们可以看到vprintf其实是通过vfprintf实现的,它的函数原型是这样的:

int DEFUN(vfprintf, (s, format, args),
register FILE *s AND CONST char *format AND va_list args)
这个函数的整体执行结构是这样的:

register CONST char *f; //可以看到f是一个const char的指针

f = format;
while (*f != '\0 ')
{

...
if (*f != '% ')
{
...
}

if (*f == '% ')
{
fc = *f++;
...
switch (fc)
{
case 'd ':
...
case 'c ':
...
....
}
}
}
从上面的结构我们可以看出,函数首先读取字符串中的字符,然后一个个比较,如果是%,则马上用switch...case结构判断后续字符

在每一个case语句块里面,都有这样的语句:

nextarg(...);
outchar(...);

nextarg()是一个宏,有如下宏定义

#define castarg(var, argtype, casttype) \
var = (casttype) va_arg(args, argtype)

#define nextarg(var, type) castarg(var, type, type)

一出现va_arg,我们就很熟悉了,这个宏的作用就是读取可变参数,在这里的作用就是将args中的内容读入。也就是利用栈顶指针读取


栈中的内容。

outchar(...)也是一个宏,它的定义如下

#define outchar(x) \
do \
{ \
register CONST int outc = (x); \
if (putc(outc, s) == EOF) \
RETURN(-1); \
else \
++done; \
} while (0)


[解决办法]
因为 printf(const char*, ... );
其中的...可以是任何类型的数据
printf内部实现的时候只是从栈上取得相应的内容,并不知道这个内容原来是什么类型的.

printf( "%d \n " , b );这个时候会把b的二进制数据,用int型来解释.
[解决办法]
printf 参数格式不正确的时候,
不会有类型转换过程,
只是把指定地址的数据按照 格式控制符 指定的类型进行解析 ~
[解决办法]
int main()
{

int a =1;
float b = 1.0;
float c = a/10; // a/10, 两个操作数均为整型, 结果为整型的0,c=0.000000
//问题一:为什么不一样啊, 用%d输出b不是一次类型转换?

printf( "%d \n ", (int)(b)); // 强制转换为int, 值为1, 但b的类型和值不发生
// 改变, 仍然为float 1.0, 所以1.0/10=0.100000
printf( "%d \n " , b ); // float型的1.0按int型输出发生上溢

//这个更奇怪了,为什么,只是把第一个%d该成%f,后面的也会发生变化?
printf( "%d , %f , %f \n ", a/10 , b/10, c ); // float型按int型输出发生上溢
printf( "%f , %f , %f \n ", a/10 , b/10, c );
/*
* 主要问题在后面这个,将整型a/10=0、float b/10=0.100000、c=0.000000全部按float输出,* 格式化输出导致数据错位
*/


getch();
return 0;


}

会得到这样的结果:
1
0
0 , 0.100000 , 0.000000
-0.000000 , 0.000000 , -1.#QNAN0
[解决办法]
前面讲的很清楚了,我是来接分的

根本原因就是,printf传参数时不转换类型,原来是什么就传入什么,但函数内部解析时又是根据控制串解析的,跟传的参数类型不一致就导致了结果的不一致

热点排行