topic 1: C预处理器 / The C Preprocessor

来源:互联网 发布:监控视频采集软件 编辑:程序博客网 时间:2024/05/21 10:36

1.1 概念 / Concept

预处理是编译执行的第一步;

虽然不是C语句,但是可以出现在程序的任何地方;

可提高代码移植性,为编译器的第二步编译提供中间文件(条件编译);

函数定义为宏时,可以避免调用函数所需的运行时开销;

1.2 文件包含 / File Inclusion

#include <linux/kernel.h>//使用<name.h>一般表示IDE提供的库头文件;
#include "scull.h"//"name.h"表示自己编写的工程头文件;
编译器预处理器根据不同写法,进行不同路径搜索:<name.h>IDE设定的搜索路径查找所需头文件,"name.h"在源文件所在位置查找该头文件,如果找不到,就去工程设置路径中去查找;(规则同具体实现有关)

预编译中,都会把这些文件名中的内容,进行展开替换;文件包含#include伪指令将所有的声明捆绑在一起,保证了所有源文件具有相同的视野;如果修改了一个头文件,则与之有依赖关系的源文件都必须重新编译;

自定义头文件常用格式:
//hello.h
#ifndef __HELLO_H__
#define __HELLO_H__
. . . //#include <others.h> 
. . . //#define PI 3.1415926
. . . //struct、extern、inline。。。
#endif

1.3 宏替换 / Macro Substitution 

#define 名字 替换文本
#define EEPROM_READ(type, addr) eeprom_read(&type, addr, sizeof(type))
其中void eeprom_read(void *type, int addr, int len)  //len = sizeof(type);

1)如果替换文本较长,可以在行末尾加反斜杠 \ ;
#define swap(t, x, y) {t _z;\
_z = y;\
y = x; \
x = _z; }  
note: 上面例子以_z不作为变量名为假设前提的;
2)  替换只对记号进行,对括在引号中的字符串不起作用,对变量名中包含替换字符的,也不进行替换;
3)宏定义里面,要对每一个变量用括号括起来;
4)注意:宏的副作用(在对数据类型进行起别名的时候,最好用 typedef,而不使用define,避免出错)
#define max(a, b) ((a) > (b)?(a):(b))    
max(i++, j++) /* error */
因为宏展开后,一个变量,重复计算了俩次,产生错误;
5)#undef 名字 取消名字的宏定义
6)参数名以#作为前缀,结果将扩展为由实际参数替换该参数的带引号的字符串
调试打印宏:#define dprint(expr) printf(#expr " = %gn", expr) 
dprint(x/y) 等价于 printf("x/y = %g\n", x/y);
7) 连接参数:##运算符。如果替换文本中的参数与##相邻,则##与其前后的空白符将被删除
#define paste(front, back) front ## back
paste(name, 1)的结果将建立记号 name1;

1.4 条件包含 / Conditional Inclusion

1)控制预处理器选择不同的代码段作为compiler的输入,产生不同的目标代码;
2)#ifdef、#ifndef 
#ifdef XXX
...do something;
#endif
3) #if #elif #else #endif
#if 常量表达式
。。。
#elif 
。。。
#else
。。。
#endif
4) defined(名字):当 名字已经定义时,值为1;否则为0;
#if !defined(__HELLO_H__)    
#define __HELLO_H__
...
#endif
note:类似#ifndef;

1.5 预定义符号常量

1)ANSI C预定义符号常量,不能用#define重新定义,也不能用#undef取消;可以换名字
#define THIS_FILE __FILE__
2)__LINE__ : 引用该符号的语句的代码行号;
3)   __FILE__ : 引用该符号的语句的源文件名称;
4)__DATE__ :字符串日期
5)__TIME__ :字符串时间;
6)__STDC__: 标示当前环境;
 
1.6 总结
 
    预编译器的功能就是完成文本的简单替换,和选择希望编译的代码段(或者变量)进入到编译阶段;
 
    skill 1:(参见uc-os-ii.h)
    #ifdef OS_GLOBALS
    #define OS_EXT
    #else
    #define OS_EXT extern
    #endif
        note: 如果在文件中,定义了OS_GLOBALS,就是空,所以会分配内存;如果没有定义名字,就使用extern;

 

    const关键字可以进行类型检查,所以人们建议多使用const,少使用define;但是define在C中还是用的非常多的;









原创粉丝点击