c语言程序的预处理

发布时间:2023-01-11 09:00

程序的翻译环境

程序的执行环境

详解C语言程序的编译+链接

预定义符号


预处理指令#define

宏和函数的对比

预处理操作符#和##的介绍

命令定义

预处理指令#include
 

程序的翻译环境

程序的翻译环境和执行环境
在任何c的实现中都存在两种不同的环境
1.翻译环境就是在这环境中源代码被转换为可执行的机器指令
2.执行环境就是实际执行代码


程序的执行环境

3.运行环境
1).程序必须载入内存中,在有操作系统的环境中,这一般由操作系统完成,
在独立的环境中,程序的载入必须由手工安排,也可能通过可执行代码置入只读内存来完成(嵌入式)
2).程序的执行便开始,接着调用main函数
3).开始执行程序代码,这时候程序将使用一个运行时的堆栈(栈帧)(并不包括堆),在使用完后就将他的地址回收,存储函数的局部变量和返回地址,
程序同时也可以使用静态(static)内存,存储与静态内存中的变量在程序的整个执行过程一直保存他们的值。
4).终止程序,正常终止main函数,也可能意外终止

 详解C语言程序的编译+链接

c语言程序的预处理_第1张图片


预定义符号

__FILE__打印当前文件所在的路径

__LINE__打印当前代码所在函数

__DATE__打印当前日期

__TIME__打印当前时间

c语言程序的预处理_第2张图片

预处理指令#define

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;
}


预处理指令#include

文件包含
1.<>直接去库函数的头文件所在的目录下查找
2.""形式的包含文件,(1).在自己写的代码底下所在的目录去查找,(2).如果1找不到,就在库函数的头文件目录下查找

嵌套文件包含
一个头文件被重复包含两次,有点啰嗦
#pragma once//头文件只包含一次,不管自己写了多少此,加上这句都只用一次
头文件中的ifndef,define ,endif是用来防止文件被多次包含

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号