程序的翻译环境和执行环境
在ANSI C的任何一种实现中,存在两个不同的环境:
第一种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第二种是执行环境,它用于实际执行代码。
翻译环境:
组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库将其需要的函数也链接到程序中。
执行环境:
程序执行的过程:
1.程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2.程序的执行便开始。接着便调用main函数
3.开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值.
4.终止程序。正常终止main函数;也有可能是意外终止。
预处理详解
预定义符号
__FILE __ //进行编译的源文件
__LINE __ //文件当前的行号
__DATE __ //文件被编译的日期
__TIME __ //文件被编译的时间
__STDC __ //如果编译器遵循ANSI C,其值为1,否则未定义
这些预定义符号都是语言内置的。举个栗子:
printf("file:%s Tine:%d\n”,__FILE__,__LINE__);
#define
#define定义标识符
语法:
#define name stuff
举些栗子:
#define MAX 1000
#define reg register //为register这个关键字创建一个简短的名字
#define do_forever for( ; 😉 //用更形象的符号替换一种实现
#define CASE break;case //在写case语句的时候自动把break写上
#define定义宏
#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)
下面是宏的申明方式:
#define name(parament-list) stuff 其中的parament-list是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
例如:
#define square(x) x*x
这个宏接收一个参数x,如果在上述声明后,你把
square(5)
写进程序中,预处理器就会用下面这个表达式替换上面的表达式
5*5
警告,这个宏存在一个问题,观察下面代码段
#define square(x) x*x
int main()
{
int a=square(5+1);
printf("%d\n",a);
return 0;
}
此时传过去后,变成了5+1*5+1,所以答案是11,并不是我们想要的6*6
所以我们可以将该宏定义改进为
#define square(x) ((x)*(x))
提示:
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号。避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
#define替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1.在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换
2.替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程
注意:
1.宏参数和#define定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。
2.当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
#的作用
#可以把一个宏参数变成对应的字符串
那么,如何将参数插入到字符串中呢?
#define PRINT(x) printf("the value of "#x" is %d\n",x)
int main()
{
int c=10;
PRINT(c);
}
#x == “x”
这里中间的#x是#将x锁定为x,不让它变为传过来的值
此时,变为printf(“the value of” “x” “is %d\n”,x)
##的作用
##可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本片段创建标识符
例如:
#define CAT(x,y) x##y
int main()
{
int class20=2022;
printf("%d\n",CAT(class,20));
}
这里的##就是将x和y连接在一起
带副作用的宏参数:
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
x+1//不带副作用
x++//带有副作用
MAX宏可以证明具有副作用的参数所引起的问题
例如:
#include <stdio.h>
#define MAX(x,y) ((x)>(y)?(x):(y))
int main()
{
int a=10;
int b=11;
int max=MAX(a++,b++);
printf("%d\n",max);//12
printf("%d\n",a);//11
printf("%d\n",b);//13
}