本文始作于2012年1月26日,刊登于人人网,于2013年2月13日迁移至此
到了晚上才开始写实验:
extern修饰函数声明。从本质上来讲,变量和函数没有区别。函数名是指向函数二进制块开头处的指针。如果文件a.c需要引用b.c中的函数,比如在b.c中原型是int fun(int mu),那么就可以在a.c中声明extern int fun(int mu),然后就能使用fun来做任何事情。就像变量的声明一样,extern int fun(int mu)可以放在a.c中任何地方,而不一定非要放在a.c的文件作用域的范围中。对其他模块中函数的引用,最常用的方法是包含这些函数声明的头文件。使用extern和包含头文件来引用函数有什么区别呢?extern的引用方式比包含头文件要简洁得多!extern的使用方法是直接了当的,想引用哪个函数就用extern声明哪个函数。这大概是KISS原则的一种体现吧!这样做的一个明显的好处是,会加速程序的编译(确切的说是预处理)的过程,节省时间。在大型C程序编译过程中,这种差异是非常明显的。
如果今天晚上搞不定,明天就得往死里整AT&T汇编,还有C语言内嵌汇编。
跟我预想的不一样,这个实验不是教你如何使用系统调用,那个你自己就应该会,这个实验教的是系统调用是如何编写出来的,是怎么工作的。
下面一段摘自linux-0.11/include/unistd.h:
1 #define _syscall3(type,name,atype,a,btype,b,ctype,c) \ 2 type name(atype a,btype b,ctype c) \ 3 { \ 4 long __res; \ 5 __asm__ volatile ("int $0x80" \ 6 : "=a" (__res) \ 7 : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \ 8 if (__res>=0) \ 9 return (type) __res; \ 10 errno=-__res; \ 11 return -1; \ 12 }
原来我们进行内核调用最终都是通过C语言内嵌汇编实现的啊!还是AT&T汇编!
这操作系统里透着一股五行八卦的气息。也许这五千年古老的智慧,以后要摄入一点易经的知识了。
预编译里面的宏展开也是一步一步的比如:
1 #define A 3 2 #define B A+1 3 #define C B*B 4 5 main() 6 { 7 printf("%d\n", C); 8 }
预编译过程是:
1 将 C 代换成 B*B; 2 再将 B 代换成 A+1 即 A+1*A+1; 3 再将 A 代换成 3 即3+1*3+1; 4 结果 C 等于 7
unistd.h中的宏展开就是这样实现的,在文件close.c中_syscall1(int,close,int,fd)就是一个宏,它连分号都没有,close.c在预编译的时候就是在上面先把unistd.c宏展开,就是把里面的全部内容都倒在上面,然后在展开这条语句的时候,利用上面已经展开好的unistd.c,递归地把这条语句展开,最终把最后一步的函数名展开出来,这才展开成最终的样子,就是:
1 int close(int fd) 2 { 3 long __res; 4 __asm__ volatile ("int $0x80" 5 : "=a" (__res) 6 : "0" (__NR_close),"b" ((long)(fd))); 7 if (__res >= 0) 8 return (int) __res; 9 errno = -__res; 10 return -1; 11 }
没想到预编译和宏展开,还有这么复杂的用途,就像前天晚上看的Makefile一样。Makefile是制作镜像时的总调度和马达,而这预编译和宏展开完成了由C语言到汇编的最关键的一步。不过想想也是,这宏展开是在预编译时进行的,不影响运行效率,而且代码上还少写很多,把这种类似递归的代换交给宏展开来完成是个绝妙的手段,这个时候用它恰到好处。不可小视的非编译语言,不可小视的脚本啊。还有就是书到用时方恨少,什么预编译,什么宏展开都是刚才现查的,当初学C++就没怎么注意这块了,当时用这个地方就那么几句话#include <stdio.h>或者#define什么的,连老师都没深追究,不过看来该学的终究还是要学的,一个都跑不了,出来混,迟早是要还的。根据这个情况来看,预编译应该在工程上还是很重要的,到时候遇到什么再说吧。
看来明天还要在干一天实验二了。不过大概意思我已经明白了,主要是因为实验指导书讲的的很明白,预估计明天中午起来,下午就能写完,这样写完之后再开始霍霍WM吧,明天先看awesome,然后半夜开始看实验三。