程序的翻译环境
程序的执行环境
详解C语言程序的编译+链接
预定义符号
预处理指令#define
宏和函数的对比
预处理操作符#和##的介绍
命令定义
预处理指令#include
程序的翻译环境
程序的翻译环境和执行环境
在任何c的实现中都存在两种不同的环境
1.翻译环境就是在这环境中源代码被转换为可执行的机器指令
2.执行环境就是实际执行代码
程序的执行环境3.运行环境
1).程序必须载入内存中,在有操作系统的环境中,这一般由操作系统完成,
在独立的环境中,程序的载入必须由手工安排,也可能通过可执行代码置入只读内存来完成(嵌入式)
2).程序的执行便开始,接着调用main函数
3).开始执行程序代码,这时候程序将使用一个运行时的堆栈(栈帧)(并不包括堆),在使用完后就将他的地址回收,存储函数的局部变量和返回地址,
程序同时也可以使用静态(static)内存,存储与静态内存中的变量在程序的整个执行过程一直保存他们的值。
4).终止程序,正常终止main函数,也可能意外终止
详解C语言程序的编译+链接
预定义符号
__FILE__打印当前文件所在的路径
__LINE__打印当前代码所在函数
__DATE__打印当前日期
__TIME__打印当前时间
预处理指令#define
define定义符号,可以提升代码的可读性
不仅可以定义数字,也可以定义代码,关键字,或者符号,
#define m 100 #define ret register//用ret来替换registr #define do_forever for( ; ;)//死循环 #define x int* #include<stdio.h> int main() { ret int b = 10; do_forever; int a = m;//100 x p=&a;//p为int*的指针变量 return 0; }
#define x int * typedef int * INT #include<stdio.h> int main() { x a,b; INT c,d; //其中只有b不是指针 //因为define只完成代码的替换,替换成了int* a,b//a是指针,b不是指针 //而typedef是对类型的重命名, return 0; }
宏和函数的对比
define 定义宏,同样是完成替换
#define机制包括一个规定,把常数替换到文本中,这种实现形式就叫做宏,或定义宏,
参数左括号必须与函数名紧邻,若中间又有空格,就会被解释为stuff中的成员,不可吝啬括号
#include<stdio.h> //不可以吝啬括号 #define square(x) x*x//建议把x加个括号(x),将其当做一个整体,括号很重要 #define double(x) (x)+(x)//将之当成一个整体才可以 #define doubl(x) ((x)+(x)) int main() { printf("%d\n", square(3));//会被替换成printf("%d",3*3); printf("%d\n", square(3 + 1));//7!=16,会被替换,宏的参数是完成替换的,不是计算的,不经过任何计算直接传过去 //会被替换成printf("%d",3+1*3+1))//7 //加括号就变成了(3+1)*(3+1) printf("%d", 10 * double(4));//这样写也是有问题的,会被替换成10*(4)+(4)=44 printf("%d", 10 * doubl(4));//这样就可以了; return 0; }
再调用宏的时候,首先对参数进行检查,是否有define定义的符号
宏不能递归,而函数可以
当预处理时,字符串常量不能被替换,如printf(“”)里的不被替换
#define m 100 #include<stdio.h> int main() { int c = max(101, m);//宏替换, printf("m=%d", m);//括号里面的m不被替换 return 0; }
预处理操作符#和##的介绍
#可以把参数插入到字符串中
#define print(x) printf("the value of " #x " is %d\n",x)//#x会变成x对于的内容所对于的字符串"a" #include<stdio.h> int main() { printf("hello world\n"); printf("hello""world\n");//结果是一样的, //写3个printf()有点冗余, int a = 10; print(a); //the value of a is 10 int b = 20; print(b); //the value of b is 20 int c = 30; print(c); //the value of b is 30 printf(""); return 0; }
##可以把两个符号合成一个符号,两个符号连在一起
#define cd(x,y) x##y #include<stdio.h> int main() { int c = 100; printf("%d", cd(c, 120));//替换成100120 return 0; }
带副作用的宏参数
首先介绍一下什么是副作用
int a=1;
int b=a+1;//b=2,a=1,没有副作用
int b=++a//b=2,而a=2这里的a就是有副作用,
#include<stdio.h> #define max(x,y) (x)>(y)?(x):(y) int main() { int a = 5; int b = 8; int c = max(a++, b++); //int c = (a++) > (b++) ? (a++) : (b++);替换 //5>8不成立,执行完判断语句,a和b就加1,a=6,b=9,则执行b++,但b++是先使用在++ //c=9,执行完后b=10 printf("%d", c);//9 return 0; }
宏和函数的对比
1.宏比函数在程序的规模上和速度上更胜一筹
2.更为重要的是,函数在定义上有数据类型限制,若定义int型数据,则double型数据就无法传参,而宏与类型无关,
3.命名规定,宏名全部大写,函数名不全部大写(不成文的规定)
命令定义
#undef移除一个宏定义
#if 加常量表达式,为0为真往下面执行
#endif为#if的结束标志
#ifdef 如果定义了就执行下面的代码
#ifndef 如果没定义就执行下面的代码
#undef//移除一个宏定义 #define m 100 #include<stdio.h> int main() { int a = m; #undef m//把定义的m取消掉 printf("%d", a);//a就没有值 return 0; }
//#if 加常量表达式(非0未真就往下执行,直到#endif停止) //#endif为#if的结束标志 //#if 0//相当于把下面的代码给注释掉, #define print 1 int main() { #if 1-2//1为真就执行,0就为假不执行,非0为真 #endif #if print//print为1为真就往下执行下面的代码 printf("hehe "); #endif return 0; }
#include<stdio.h> int main() { #if 1==1//判断成立,就往下执行,从多分支只选择一个,选择完下面就不执行跳到#endif去 printf("hh"); #elif 1 == 2 printf("haha"); #else printf("hehe"); #endif return 0; }
//判断是否被定义的写法 #include<stdio.h> int main() { #ifdef test//如果test被定义了,下面参与执行,给个0也可以 printf("test"); #endif #ifndef hh//如果hh不定义,下面参与编译 printf("hehe"); #endif return 0; }
预处理指令#include
文件包含
1.<>直接去库函数的头文件所在的目录下查找
2.""形式的包含文件,(1).在自己写的代码底下所在的目录去查找,(2).如果1找不到,就在库函数的头文件目录下查找
嵌套文件包含
一个头文件被重复包含两次,有点啰嗦
#pragma once//头文件只包含一次,不管自己写了多少此,加上这句都只用一次
头文件中的ifndef,define ,endif是用来防止文件被多次包含