5,#line预处理 6,#pragma预处理 7,#运算符 8,##运算符
预处理名称 | 意义 |
#define | 宏定义 |
#undef | 撤销已定义的宏名 |
#include | 使编译程序将另一源文件嵌入到带有#include 的源文件中 |
#if | #if 的一般含义是:如果#if后面的常量表达式为true ,则编译它与#endif之间的代码, 否则跳过这些代码 |
#else | |
#elif | |
#endif | |
#ifdef | 用#ifdef与#ifndef命令分别表示“如果有定义”与“如果无定义”, 是条件编译的另一种方法 |
#ifndef | |
#line | 改变当前行数和文件名称 |
#error | 编译程序时,只要遇到#error 就会生成一个编译错误提示消息,并停止编译 |
#pragma | 为实现时定义的命令,它允许向编译程序传送各种指令 |
__LINE__表示正在编译的文件行号。
__FILE__表示正在编译的文件的名字。
__DATE__表示编译时刻的日期字符串,例如:“25 Dec 2007”。
__TIME__表示编译时刻的时间字符串,例如:“12:30:55”。
__STDC__判断该文件是不是定义成标准C程序。
【注意】如果编译器不是标准的,则可能仅支持以上宏的一部分,或根本不支持。当然编译器也有可能还提供其它预定义的宏名。宏名的书写由标识符与两边各二条下划线构成。
预编译:
a.处理所有的注释,以空格代替。
b.将所以#define删除,并展开所有的宏定义,字符串替换。
c.处理条件编译指令#if,#ifdef,#elif,#else,#endif
d.处理#include,并展开被包含的文件,把头文件中的声明,全部拷贝到文件中。
e.保留编译器需要使用的#pragma指令、
怎么样观察这些变化呢?最好的方法就是在GCC中,输入预处理指令,可以看看不同文件经过预处理后变成什么样了,
预处理指令:gcc -E file.c -o file.i 注意:-C -E一起使用是预编译的时候保留注释。
编译:
a.对预处理文件进行一系列词法分析,语法分析和语义分析
词法分析:主要分析关键字,标示符,立即数等是否合法
语法分析:主要分析表达式是否遵循语法规则
语义分析:在语法分析的基础上进一步分析表达式是否合法
b.分析结束后进行代码优化生成相应的汇编代码文件 编译指令:gcc -S file.c -o file.s
汇编:
汇编器将汇编代码转变为机器可以执行的指令,每个汇编语句几乎都对应一条机器指令,其实机器指令就是机器码,就是2进制码。汇编指令:gcc -c file.c -o file.o 注意:-c是编译汇编不连接。
链接:
再把产生的.o文件,进行链接就可以生成可执行文件。连接指令:gcc file.o file1.o -o file 这句指令是链接file.o和file1.o两个编译并汇编的文件,并生成可执行文件file。
链接分两种:静态链接和动态链接,静态链接是在编译器完成的,动态链接是在运行期完成的。静态链接的指令是:gcc -static file.c -o file对于一些没有动态库的嵌入式系统,这是常用的。
一般要想通过一条指令生成可执行文件的指令是: gcc file.c -o file
资料:这里面说到了很多关于gcc的使用的问题,我提资源下载地址http://download.youkuaiyun.com/detail/qq418674358/6041183
【问题1】数值宏常量,例如:#define PI 3.14
在写程序的时候,尽量不要使用“魔数”。
const修饰的数据是有类型的,而define宏定义的数据没有类型。为了安全,建议在定义一些宏常数的时候用const代替,编译器会给const修饰的只读变量做类型校验,减少错误的可能。但注意:const修饰的不是常量而是readonly的变量,const修饰的只读变量不能用来作为定义数组的维数,也不能放在case关键字后面。(在VS2008测试下,发现可以呀?)
【问题2】字符串宏常量
#define ENG_PATH_1 "C://windows" (在定义路径的时候常用)
【问题3】用define宏定义注释符号正确吗?(错误)
- #define BSC //
- #define BMC /*
- #define EMC */
- BSC this is my single-line comment
- BMC this is my multi-line comment EMC
上面是不正确的。因为注释先于预处理指令被处理。
【问题4】用define宏定义表达式
记住:define是个演技高超的替身演员,但也经常耍大牌。要搞定它其实很简单,别吝啬使用括号就行了。
【问题5】宏定义中的空格
#define SUM (x) (x)+(x) // error
编译器认为这是定义一个宏:SUM,其代表的是(x) (x)+(x) 。
关键问题是在于,SUM后面的这个空格。一定要知道什么时候该用空格,什么时候不该用空格。这个空格仅仅在定义的时候有效,在使用这个宏函数的时候,空格会被编译器忽略掉。
【问题6】#undef
#undef是用来撤销宏定义的。
- #define PI 3.14
- // some codes
- #undef PI
- // the below codes can not use macro IP again
【思考】变量z等于多少?
- #define X 3
- #define Y X*2
- #undef X
- #define X 2
- int z=Y;// 4
3.2 条件编译
条件编译有3种形式:
(1)第一种形式:
#ifdef 标识符
程序段1
#else
程序段2
#endif
上面这种形式的功能是:如果标识符已被#define命令定义过,则对程序段1进行编译;否则对程序段2进行编译。
(2)第二种形式:
#ifndef 标识符
程序段1
#else
程序段2
#endif
这种形式的功能是:如果标识符未被#define命令定义过,则对程序段1进行编译;否则对程序段2进行编译;
(3)第三种形式:
# if 常量表达式
程序段1
#else
程序段2
#endif
这种形式的功能是:如果常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。因此可以使程序在不同条件下完成不同的功能;
1.)格式1:
#include <filename>
其中,filename为要包含的文件名称,用尖括号括起来,也称为头文件,表示预处理到系统规定的路径中去获得这个文件(即C编程系统提供的并存放在指定的子目录下的头文件)。
2.)格式2:
#include "filename"
其中,filename为要包含的文件名称,双引号表示预处理应在当前目录中查找文件名为filename的文件;若没有找到,则按系统指定的路径信息搜索其他目录。找到文件后,用文件内容替换该语句。
#include “” 和<> 的区别 这是很多校园招聘中笔试题都会出现的:
<> 表示:预处理到系统规定的路径中去获得这个文件
“”双引号表示:预处理应在当前目录中查找文件名为filename的文件