目录
1.程序的翻译环境和执行环境
编辑
2.编译+链接
运行环境
3.预处理
预定义符号
#define
#与##
带副作用的宏参数
宏和函数的对比
命名约定
编辑
#undef编辑
命令行定义
编辑
条件编译
文件包含
嵌套文件包含
4.其他预处理指令
1.程序的翻译环境和执行环境
在ANSL C的任何一种实现中,存在两个不同的环境
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码。
2.编译+链接
组成一个程序的每个源文件通过编译过程分别转换成目标代码 (obiect code)
每个目标文件由链接器 (linker) 捆绑在一起,形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。
integrated development environment
1.预处理选项gcc -E test.c -o test.i
预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中
2.编译选项 gcc-S test.c
编译完成之后就停下来,结果保存在test.s中。
3.汇编gcc -c test.c
汇编完成之后就停下来,结果保存在test.o中
运行环境
3.预处理
预定义符号
示例:
#define
示例:
#define后面要加;吗?
eg:#define MAX 100;
加了;就代表MAX被“100;”替换 可能引起语法错误呦
示例:
注意与函数的区别:
定义宏是直接替换,而不是像函数一样传具体的值
那这样是不是就可以解决一些函数中类型不一样无法写成一个函数的问题捏?
是滴!
注意:
参数列表的左括号必须与name紧邻
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分
一些小小的注意事项:
示例:(X*X) 与 ((X)*(X)) 的区别
#与##
示例:
宏替换
#:替换参数对应的字符串 而不是值
替换之后如下:
示例:(连接作用(将分离合成整体))(但合成的整体必须是有定义的)
打印出的结果为:100
带副作用的宏参数
示例:
宏和函数的对比
宏通常被应用于执行简单的运算
比如在两个数中找出较大的一个
#define MAX(a,b) ((a)>(b)?(a):(b))
那为什么不用函数来完成这个任务?
函数会:调用——>计算——>返回(小型运算)
宏的缺点:
当然和函数相比宏也有劣势的地方:
1.每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2.宏是没法调试的。
3.宏由于类型无关也就不够严谨
4.宏可能会带来运算符优先级的问题,导致程容易出现错
示例:
命名约定
#undef
示例:
命令行定义
条件编译
示例:
3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
4.嵌套指令
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();#endif
#endif
#endif
示例:
上面两种写法等价
那条件编译与if else语句有何不同捏?
条件编译在预处理阶段就已经把不要的代码删掉了,而if else语句的代码还在留着
文件包含
文件包含
我们已经知道,#include 指令可以使另外一个文件被编译。就像它实际出现于#include 指令的地方
一样。
这种替换的方式很简单
预处理器先删除这条指令,并用包含文件的内容替换。这样一个源文件被包含10次,那就实际被编译10次。
VS环境的标准头文件的路径:
c:\Program Files (x86)\Microsoft visual studio 12.0\vc\include
//这是VS2013的默认路径
查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。
这样是不是可以说,对于库文件也可以使用“”的形式包含?
答案是肯定的,可以。
但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。
示例:
嵌套文件包含
如何解决这个问题?
答案:条件编译。
每个头文件的开头写
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif //__TEST_H__
或者
#pragma once
就可以避免头文件的重复引入。
示例:
4.其他预处理指令