宏定义妙用之: 让编译器(预处理)干尽可能多的事情
鉴于我们日后要70岁才退休,社保要交40年的中国特色的趋势
我们程序员没有理由不珍惜生命,让编译器做更多的事情
先看main.c 文件如下:
#include <stdio.h>#include <stdlib.h>extern int sys_read();extern int sys_write();#define __NR_syscalls 100#define __SYSCALL(nr, call) [nr] = (call),void *sys_call_table[__NR_syscalls] = {#include "systemcall.h"};int main(){ for(;;); return 0;}systemcall.h 文件如下:
而在unistd.h头文件中(linux的系统调用有几百个):
#define __NR_read 63__SYSCALL(__NR_read, sys_read)#define __NR_write 64__SYSCALL(__NR_write, sys_write)
最终预编译之后的结果应该像下面的样子是,我猜的:
void *sys_call_table[__NR_syscalls] = {
[63]=sys_read,
[64]=sys_read
下面我们花点宝贵的时间来验证下:
gcc -E ./main.c > pre.txt
我们只是预编译,看下输出:
void *sys_call_table[100] = {# 1 "./systemcall.h" 1[63] = (sys_read),[64] = (sys_write),# 12 "./main.c" 2};int main(){ for(;;); return 0;}与当初预想的一致。
优点:
0 : 节省了输入字符的时间:)
1: sys_call_table的填充时候,
可以避免索引号与函数指针不匹配的问题(前提是头文件没有写错)
2: 能让编译器去做的时候,当然比让人工去保证可靠
缺点:
代码的可阅读性减低很多
参考:kernel/arch/score/kernel/sys_call_table.c
(其实很多地方也有用到,如kill命令的实现,android解析init.rc文件的时候)