发布时间:2023-01-11 09:00
程序的翻译环境和执行环境
在任何c的实现中都存在两种不同的环境
1.翻译环境就是在这环境中源代码被转换为可执行的机器指令
2.执行环境就是实际执行代码
3.运行环境
1).程序必须载入内存中,在有操作系统的环境中,这一般由操作系统完成,
在独立的环境中,程序的载入必须由手工安排,也可能通过可执行代码置入只读内存来完成(嵌入式)
2).程序的执行便开始,接着调用main函数
3).开始执行程序代码,这时候程序将使用一个运行时的堆栈(栈帧)(并不包括堆),在使用完后就将他的地址回收,存储函数的局部变量和返回地址,
程序同时也可以使用静态(static)内存,存储与静态内存中的变量在程序的整个执行过程一直保存他们的值。
4).终止程序,正常终止main函数,也可能意外终止
__FILE__打印当前文件所在的路径
__LINE__打印当前代码所在函数
__DATE__打印当前日期
__TIME__打印当前时间
define定义符号,可以提升代码的可读性
不仅可以定义数字,也可以定义代码,关键字,或者符号,
#define m 100
#define ret register//用ret来替换registr
#define do_forever for( ; ;)//死循环
#define x int*
#include
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
int main()
{
x a,b;
INT c,d;
//其中只有b不是指针
//因为define只完成代码的替换,替换成了int* a,b//a是指针,b不是指针
//而typedef是对类型的重命名,
return 0;
}
define 定义宏,同样是完成替换
#define机制包括一个规定,把常数替换到文本中,这种实现形式就叫做宏,或定义宏,
参数左括号必须与函数名紧邻,若中间又有空格,就会被解释为stuff中的成员,不可吝啬括号
#include
//不可以吝啬括号
#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
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
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
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
#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
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
int main()
{
#if 1==1//判断成立,就往下执行,从多分支只选择一个,选择完下面就不执行跳到#endif去
printf("hh");
#elif 1 == 2
printf("haha");
#else
printf("hehe");
#endif
return 0;
}
//判断是否被定义的写法
#include
int main()
{
#ifdef test//如果test被定义了,下面参与执行,给个0也可以
printf("test");
#endif
#ifndef hh//如果hh不定义,下面参与编译
printf("hehe");
#endif
return 0;
}
文件包含
1.<>直接去库函数的头文件所在的目录下查找
2.""形式的包含文件,(1).在自己写的代码底下所在的目录去查找,(2).如果1找不到,就在库函数的头文件目录下查找嵌套文件包含
一个头文件被重复包含两次,有点啰嗦
#pragma once//头文件只包含一次,不管自己写了多少此,加上这句都只用一次
头文件中的ifndef,define ,endif是用来防止文件被多次包含