C语言深度解剖——读书笔记-5、预处理
来源:互联网 发布:国鑫金服行情软件 编辑:程序博客网 时间:2024/06/18 11:54
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
为实现时定义的命令,它允许向编译程序传送各种指令
另外,ANSI标准C还定义了如下几个宏:__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.csdn.net/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的文件
- C语言深度解剖——读书笔记-5、预处理
- C语言深度解剖——读书笔记-6、预处理
- 读书笔记《c语言深度解剖》(5)
- C语言深度解剖——读书笔记(数组和指针)
- C语言深度解剖——读书笔记-1、关键字
- C语言深度解剖——读书笔记-2、关键字
- C语言深度解剖——读书笔记-4、符号
- C语言深度解剖——读书笔记-12、内存管理
- C 语言深度解剖 读书笔记
- 《C语言深度解剖》读书笔记
- 《C语言深度解剖》读书笔记
- C语言深度解剖读书笔记
- C语言深度解剖读书笔记
- C语言深度解剖读书笔记
- C语言深度解剖读书笔记
- C语言深度解剖读书笔记
- C语言深度解剖读书笔记
- C语言深度解剖读书笔记
- 网络流---ISAP
- linux_c开发(5-3)进程间通讯_信号通讯
- Java 之工厂方法和抽象工厂模式
- 网络流---Dinic
- 二叉树的遍历与二叉树的深度
- C语言深度解剖——读书笔记-5、预处理
- 周赛-Expression
- A Simple Review Of 《Query Languages for Graph Databases》(I)
- 我在CSDN的开始
- linux FTP配置
- 一些工具类
- 在64位ubuntu上编译kitkat4.4时遇到HashSet_jni.h错误导致编译中止的问题
- 1031. Hello World for U (20)
- 【登录异常解决】Ubuntu 输入正确的密码后重新返回到登陆界面