一,C语言程序的运行
C语言程序会从.c文件一步一步转化为.exe可执行文件,
一般分为三个阶段:编译.链接,运行
编译细分为:预处理,编译,汇编
编译
预处理
在预处理阶段,会将程序里面的宏定义,预处理命令,以及注释等替换,生成.i文件,注释被替换为一个空格,头文件会包含
编译
在编译阶段,会将C语言程序翻译为汇编语言生成.s文件,并进行
1.词法分析 2.语义分析 3.语法分析 4.符号汇总
汇编
生成符号表,并将汇编代码翻译为二进制命令,生成.obj文件
链接
将目标文件和链接库链接,合成段表,符号表的合并和重定义,生成可执行的二进制程序
运行
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序 的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用main函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。
二.预处理命令
1.预处理符号
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义
2.define定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义 宏(define macro)。
下面是宏的申明方式: #define name( parament-list ) stuff 其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意: 参数列表的左括号必须与name紧邻。 如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
宏本质上只是在预处理中对其替换,并不是像函数那样;所以如果不注意就会出现各种问题
比如这个宏定义
#define SQUARE( x ) x * x
如果我这么使用 SQUARE( 2 + 1) 结果就会变成2+1*2+1=5,而不是9,所以我们在定义宏的时候尽量将每一个参数都使用括号
#define SQUARE( x ) (x) * (x)
这样就能避免因为操作符顺序出现的问题,
3.#define 替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。 1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。 2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。 3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。 注意: 1. 宏参数和#define 定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。 2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
4.#和##
使用 # ,把一个宏参数变成对应的字符串。比如
#define PRINT(FORMAT, VALUE)\
printf("the value of " #VALUE "is "FORMAT "\n", VALUE);
PRINT("%d", 3*3);
结果是the value of 3*3 is 9,
##可以把位于它两边的符号合成一个符号。 它允许宏定义从分离的文本片段创建标识符,比如
#define ADD_TO_SUM(num, value) \
sum##num = value;
...
ADD_TO_SUM(2, 10);//作用是:给sum1赋值为10.
这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
5.#undef
这条指令用于移除一个宏定义。如果现存的一个名字需要被重新定义,那么它的旧名字就可以使用这个使其被移除。
三.条件编译
常见的条件编译指令:
1. #if 常量表达式 //... #endif //常量表达式由预处理器求值。 如:
#define __DEBUG__ 1
#if __DEBUG__
...
#endif
2.多个分支的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
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