提到预处理,不由想起来一个经典问题。
C语言简单吗? 简单,C语言没多少语法,很快就学会。
的确,C语言如果没有预处理,的确会简单很多。但一旦有了,就复杂度上升了好几个等级。
C语言支持面向对象吗? 可以,预处理能帮你实现。
C语言有异常处理吗?可以,预处理能帮你实现。
预处理就是一个潘多拉盒子,可以让你上天堂,也可以让你下地狱。(笑话)
在认真学习C语言时,建议下载C语言规范:
C89 嵌入式领域使用得多,芯片公司提供的工具很多还不支持C99
C99
规范不是用来看的,是用来查的。(笑话)
关于C语言编译器代码,可以参考下面2个:
TinyCC (http://bellard.org/tcc/)
gcc (http://mirror.bjtu.edu.cn/gnu/gcc/)
实际项目中用得最多的就是下面几个:
#include 文件
注意:不要受C语言教材的影响,以为只可以加载.h文件。这是一个最大的思维定式。
可以加载任何文本文件。
比如 test.test 内容如下:
int myTestAry[] = { 0, 1, 2,3 ,4, 5};
#include "test.test"
这样,有什么好处呢?
最大的好处是可以和其他语言结合。
比如,我们可以用Python生成符合C语言语法的文本,比如,字体数据,图片数据等。
#define
#ifdef
#undef
#if
#endif
5个指令一起配合,能对源代码进行版本控制。
比如最常见的
#ifdef WIN32 /* 如果当前系统是WIN32平台 */
#endif
当然,#define定义的控制变量,也可以在编译脚本中用 -D变量名=变量值 替换。
#define 还有一个常见的作用是定义常量。
#define PI 3.1415926
不过,这些都是小用途。
真正强大的是用#define构建复杂机制。可惜,实际项目中为了可读性,基本被禁止。
有兴趣的可以搜,C语言与面向对象 C语言与异常处理 C语言与模板 或者看MFC中的宏。
这是一个让人痛苦并快乐的功能。
实际项目中用得最多的是打印Log语句。
比如跟踪函数执行:
#define FUNC_BEGIN() do { printf("Enter %s %d \n", __FUNCTION__, __LINE__); } while(0)
#define FUNC_END() do { printf("Leave %s %d \n", __FUNCTION__, __LINE__); } while(0)
在函数进入的地方,加
FUNC_BEGIN();
函数返回的地方加:
FUNC_END();
更复杂的打印语句:
#define MYPRINT(...) do { printf(__VA_ARGS__); } while(0)
__FUNCTION__: 当前函数名,由编译器决定
__LINE__: 当前代码行号
__VA_ARGS__: 可变参数
#error
编译报错。可以在代码中加下面语句进行测试下。()
#error "不支持"
#pragma
控制编译器,与编译器实现有关。
实际项目中为了可移植性用得不多。
对于特定项目,建议使用前需要参考编译器说明,并在项目风险管理中加以说明。(这一点很重要,对项目跨平台移植很有意义)
总而言之,预处理是一个编译器展示自我的地方,也是一个让大家疯狂,让大家迷失的地方。
对于开发者来说,这就是天堂,对项目经理来说,这就是地狱。()