C语言中Printf()函数的运行机制


printf()是用来输出一个格式化的串的;它的参数个数是不确定的;可以有多一个;

但必需有一个;就是第一个格式串.这个不能缺.第一个参数要求是const char*

但你也可以使用char* ,只是你最好使用一个const char*;这样是安全的;

这一个涵数的第一个用法也是最简单的使用方法就是printf(str);

如:printf("hello world");

第二种使用方法是串中存在其他格式;

如: printf("this is a number %d",i);

%d告诉printf要把i格式成一个整型数据来输出;如果i==2;

那么输出是this is a number 2

就这二种方法;格式%输出还有很多种情况%f %c ....;但在这里我不想谈论这个格式问题;

因为书上说了很多...

在这里我要说的是printf是怎么使用参数的;如果有人格式化时候出现逻辑错误;为什么输出的是那样的结果;  【 帮客之家 www.Linuxidc.com 】

我要说的是结果为什么是那样而不是这样.也许这正是新手真正想了解的:

第一步,先了解printf是怎么传递参数的;printf()是通过把参数从右到左的顺序压栈的;

如printf("a=%d b=%d",i,j);会先压j然后压i然后压这个串"a=%d b=%d"的首地址

所以这个调用总共要压三个参数;

不管你要几个参数都好,第一个参数一定要是一个串的地址;这个地址是最后压栈的;

printf知道你传来几个参数吗?

不知道!!!

它首先关心的是最后压进来的参数(就是"a=%d b=%d"这个串的首地址);

然后printf对这个串进行检查;如果发现存在%格式化要求.它就认为倒数第二个存在参数(不管是否真的存在)要以%所要求的

格式输出;如%c要以字符来输出一样;

如果你串中有这种格式,而你却没给传过去参数.情况会怎么样?如这样:printf("this is %d");

printf会认为你确实传过来了;尽管你真的没有传;它都会以第格式串的上面压有一个参数;

它会去取那个空间的数据出来按格式输出;此时候那个空间应该是属于上一级的涵数的栈空间;

所以输出多部分是随机的;鬼才知道哪里存放的是什么;

所以printf()是靠串的格式来判断参数的多少的;但如果错了;程序一般情况还是能很好的运行;

因为它只读栈不写;所以没有破坏性;

而且参数的清空责任是有调用他的涵数来负责的,所以栈总能平衡.

好了;该说说你的程序了;

你printf("the is a int %d"+i); 是吧?这样传了几个参数呢?

一个!

这个参数是什么呢?是"the is a int %d"的首地址加上i的和;

printf是怎么看这个参数的呢?printf认为它是一个需要格式输出的串的首地址;

我们知道i=10;

所以当它把首地址加i就是加10后;地址就跑到N这个字母哪里了;

所以就从n那里开始输出;当它遇到%d的时候;

它就认为你还传来一个需要以%d格式输出的数;所以它就去串地址所压的地方的上面取参数;

当然这样只会取到起上一级的涵数的栈空间的数据;

如在你的程序中;我所说的上一级的涵数就是main()

所以就取上一级的栈空间里的东西;如i就是main()栈里的

MASTERRAY的实验是输出10;但我说这个10是偶然的;没有必然;就是随机的;它可以随编译器的不同而不同;随优化设置不同而不同;

如果你用VC6.0运行你就发现它不是10;但确定的是从nt处开始;只有一种情况才是10;那就是就在call printf前没有任何push操作;

这样栈里的i就能很靠近压在栈里的参数;只有靠近才能输出i;总之它只拿压参数之前所压的东西;PUSH 参数之前PUSH的是什么,;那就

是什么。。

相关内容