一直以来想写技术博客,但迟迟未行动,如今终于下定决定,还是来写一写,顺便巩固一下自己的知识。
废话不多说,就参照《C语言程序设计(第2版)》,从头过一遍吧。
1.Hello World
一开头,基本是每个程序员都熟悉的第一个程序:
#include <stdio.h>
int main()
{
printf("Hello world!\n");
return 0;
}
也许很多人会觉得:这没什么啊,不就一句向控制台打印一句Hello world 吗?但我想的是通过这个去了解更多的东西,因为很多人(包括我)在写了很久程序之后,才明白了什么叫“语言”,什么叫“库”,C语言本身是没有任何的“printf”给你用的。
那第一句 "#include <stdio.h>" 表明: 我要引入一个名叫 "stdio.h"这样的文件库,里面有一个叫"printf"的函数。
第二句"int main()" 表明: 这是程序的入口,为何要用"main"做入口?因为编译器就这么找的,游戏规则你得遵守,你要是高兴,完全可以自己写个编译器,规定一个名叫“fuck you”的函数入口。
第三句”printf("Hello world!\n")“, 表示调用了一个名叫printf的函数,传给它一个字符串指针,当然你得明白,这里是常量字符串指针。
那我们来研究下printf()是如何实现的。
在这句上打个断点,然后执行:
跟进去:
这尼玛是个鸟? 这么简单一句里面还这么复杂?
我们一个个的来看,可以看见”Hello world\n“传进来了。
”va_list“ 是个毛? 这玩意实际上就是个 char * 的指针,暂且不管其他两个 buffing 和 retval,来看下面有个宏 "va_start",找到它的定义:
我擦,这又是毛? 跟进去再看看
这个很明白,就是取个地址而已。
这个?尼玛跟天书一样,又是减又是位运算的,一开始我也不懂,后面网上搜了下别人的讲解才知道,这个是保证内存对齐的玩意,很高端,至今我还有点迷糊,不过不用过分纠结。反正就是计算它大小
我们回到刚才这句:
这句可以简单理解为: arglist = (va_list)(&format) + sizeof(format)
取传进来字符串指针的地址,再加一个sizeof(char*) ? 这是搞鸡毛?我理解了很久,才初步推断这是函数调用时把参数压栈,然后这样那首参数地址加一下第一个参数的大小,自然也就得到了第二个参数的地址(也就是我们写: printf("This num is : %d",n) 这个n的地址), 不知这样理解对否? 还请高手指教。
那这意思明了了,就是arglist现在只想后面不定参数的第一个参数。
再往下,这句
再跟进去:
OK,了解了这是给stdout加个锁,至于什么是锁我想不用多说,了解点多线程的都知道的。
那传进来的stdout,我们再看看它到底是个什么鸟,虽然一直听,我想自己去研究的貌似还挺少。
跟过去:
再进__iob_fun(
)
再跟:
噢,Bitch,终于找到你了,是个FILE的数组,这里_IOB_ENTRIES设了上限是20,可以看见有三个初始就有的大家经常听见的“stdin”,“stdout”,"stderr"。
找到FILE的定义:
就这么个玩意。说到这里我想说一下,有很多初学者认为这个语言屌,那个语言妙,其实说白了还不就是一些基本的东西组成的,再往下就是二进制了。所以与其纠结于XX语言好,XX语言妙,不如探究下本质,我也是因为想从本质上去发现语言,才有了写文的初衷。
扯回来,这里我们大概知道怎么回事了,printf一进来就把输出流锁住,然后进到这里来:
这里做一些初始的检查工作之类的,暂且不管。
主要看这一句:
撸进去:
我草?这是个毛,里面这么混乱,printf里面这么屌它妈妈知道吗?
暂且不要过于纠结这么多参数以及略长的函数以及复杂的循环,我们找找主要的,
到这里:
终于,这个传进来的"Hello World\n"开始起作用了,真麻烦啊。。。。
可以看见它在扫描 format这个字符串 ,也就是“Hello Wordl\n”,一直扫到末尾"\0"结束符。中间还有很多的杂七杂八的判断之类的,什么语言区啦,状态啦,然后麻痹的一长串恶心的switch case ,终于来到这句:
往里面写,也就是把当前扫描到的往 stdout这个buf里写,因为这里没有带什么“%s%d”之类的,所以处理过程还是相对比较简单。
噼里啪啦写完了之后:
返回 往里面写了多少个字符。OK,这个函数执行完了,临时的buffing里面已经有了内容。
最后_ftbuf 把buffing的内容填充到stdout里面去,至此,终于差不多完了。
之前我们锁了stdout,有锁当然就要解锁:
然后返回写入的字符 :
然后刚才调用的函数传的参数弹栈,也就是“Hello World\n”这个常量字符串指针变量弹出来,回到mian函数:
最后返回0,OK,至此我们的Hello World便完成了。
这里 只讲到了va_list va_start 没有说 va_arg,因为初篇只有“Hello World\n”这么个简单的字符串,所以没有提及复杂的处理,后面会讲到。
初次写作,还请大家批评指正。
ps.转载的话(估计也没人转 ,有人看没有都是一回事╮(╯_╰)╭),还是注明个出处吧?