编程语言
636
一、翻译环境和执行环境
翻译环境:在这个环境中源代码被转换为可执行的机器指令 执行环境:用于实际执行代码
具体什么意思我们通过画图来解释
1.翻译环境
翻译环境分为两步,编译和链接
那么编译和链接是什么呢,同样以图来说明
那么问题又来了,编译和链接的过程中发生了什么
由于编译和链接内部需要Linux环境深入了解,这里直接上定义
2.执行环境
简述一下程序执行的过程
1.程序必须载入内存中. 在有操作系统的环境中:一般由操作系统完成 在独立的环境中:程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存完成 2.程序执行便开始,调用main函数 3.开始执行程序代码.这个时候程序将使用一个运行的堆栈(stack)(堆栈就是栈),存储函数的局部变量和返回地址. 程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值. 4.终止程序.正常终止main函数,也可能是意外终止.
以上
二、预处理详解
1.预定义符号
__FILE__ //进行编译的源文件 %s __LINE__ //文件当前的行号 %d __DATE__ //文件被编译的日期 %s __TIME__ //文件被编译的时间 %s __STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义 %d
三、#define定义宏
#define允许把参数替换到文本中 勤加()
①#
#可以把参数替换到字符串中
引出一下常见情况
void print(int x) { printf("??的结果是%d\n",x); // ?? 里面到底放什么呢 //显然函数并不能做到这个功能 } int main() { int a = 10; //打印出: a的结果是10 print(a); int b = 20; //打印出: b的结果是20 print(b); int c = 30; //打印出: c的结果是30 print(c); }
所以我们使用宏
首先我们要知道
printf("halo"); printf("ha""lo"); //这两个代码的结果是一样的,由此
#define print(X) printf(#X "的结果是%d",X) int main() { int a = 10; //打印出: a的结果是10 print(a); //本质上来讲,替换后 printf(#X "的结果是%d",X); printf("a" "的结果是%d",X); int b = 20; //打印出: b的结果是20 print(b); int c = 30; //打印出: c的结果是30 print(c); }
//格式不同的处理 #define print(X,FORMATE) printf(#X "的结果是"FORMATE,X) int main() { int a = 20; //打印出: a的结果是20 print(a, "%d\n"); float b = 5.5; //打印出: b的结果是5.5 print(b, "%f\n"); }
注意:#不能直接用在printf中,只能在宏内使用
②##
直接举个例子
#define CAT(X,Y) X##Y##Z int main() { int class1011 = 100; printf("%d\n",CAT(class,10,11)); printf("%d\n",class1011); //两者打印结果相同,可以将##看作是一个连接符号 return 0; }
四、宏和函数的取舍
属性 | #define定义宏 | 函数 |
---|---|---|
代码长度 | 每次使用时,宏代码都会被插入程序中.除了非常小的宏除外,程序的长度会大幅提升 | 函数代码只出现于一个地方,每次调用这个函数时,都调用那个地方的同一份代码 |
执行速度 | 更快 | 存在函数的调用和返回的额外开销,所以相对较慢 |
操作符优先级 | 宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写时多些括号 | 函数参数只在函数调用的时候求值一次,它的结果值传递给函数.表达式的求值结果更容易预测 |
带有副作用的参数 | 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果 | 函数传参只在传参的时候求值一次,结果更容易控制 |
参数类型 | 宏的参数与类型无关,只要对参数的操作时合法的,它就可以使用于任何参数类型 | 函数的参数与类型有关,如果参数的类型不同,就需要不同的函数 |
调试 | 宏是不方便调试的 | 函数是可以逐语句调试的 |
递归 | 宏不能递归 | 函数可以递归 |
以上
五、undef
该指令可以移除一条宏定义 比如说
#undef NAME
六、条件编译
先上一个例子
#define ADD int main() { #ifdef ADD //如果定义了ADD宏,那么endif前就可以运行,反之则会在预处理时被略过 printf("666"); #endif #if 1 //非零则进入,否则在预处理时被略过 printf("666"); #endif return 0; }
#ifdef 后跟宏名称 #if 后跟常量表达式 同样都是以#endif作为结尾
同样的还有#else 、#elif
其后面跟的都是常量表达式
int main() { #if 1==1 //常量表达式 printf("666"); #elif 2==2 //常量表达式 printf("999"); #else 3==3 //常量表达式 printf("114514"); #endif //同if else 一样,这三条语句只能进入一个,不能同时进入 return 0; }
也有
#ifndef 作用与 #ifdef相反 #if defined() 括号内加入宏名,作用与 #ifdef相同 也可以#if !defined(),作用与 #ifdef相反