栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c语言学习之路————预处理1.0

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c语言学习之路————预处理1.0

我们的程序在从我们的.c源文件到.exe可执行文件会经过编译和链接的过程,在这个过程中有两个环境

翻译环境:

编译:就是生成.obi目标文件的过程,在这个中项目每一个源文件都会经过编译器生成一个目标文件,再通过链接器,将在所有的目标文件和链接库(静态库、动态库,类似于头文件里的函数库)链接起来生成可执行文件,而编译也分为几个过程预编译、编译、汇编过程才能生成.obj文件。预编译过程会打开头文件,头文件里的内容会被包含到我们的程序源文件中:还会用空格替换掉程序里的注释;还会对#define定义的符号,进行替换,所有的预处理阶段进行的是文本操作,把该替换的替换掉生成.i(gcc)文件;编译的过程是将我们的代码编译成汇编代码,生成.s(gcc)文件,这个过程还包括,语法分析,词法分析,语义分析,还有符号汇总(这里的符号包括一些函数名啊之类的exp:main,全局变量);汇编过程会生成.o文件,形成符号表(在汇总符号之后会形成一个符号表,内容是程序里的符号以及这些符号的地址,队友重复的符号,也会进行判断合并),还有将汇编指令转化成二进制指令

链接:生成可执行文件的过程,包含合并段表,符号表的合并和重定位,这里提到的段表,是由于每个生成的目标文件都是有固定的格式的,通过格式将目标文件分成好几个段形成段表,而这种格式叫elf文件格式,而每个.o文件进行链接的时候会将相应段上的数据按照一定规则合并到一起,这个过程叫做合并段表;在一个源文件中声明函数的函数符号是没有有效地址的,假设我们在一个函数中要使用另一个文件中的函数,需要extern指令,而这时的外应用函数的函数符号,没有有效地址,所以要结合拥有着函数的文件,在合并符号表的时候会将拥有这个函数的相应函数符号以及地址,与要使用这个函数的文件符号表进行合并,只放那个有有效地址的符号,以便可以找到这个函数。

预处理选项:gcc -E text.c -o text.i

编译选项:gcc -S text.c

汇编选项:gcc -C text.c

运行环境:

运行程序必须载入到内存中,这个一般又操作系统完成,而独立的环境下,需要手动载入。载入内存中之后,便开始调用main函数,最终以main函数结束。

1.预编译——预定义符号

__FILE__      代码所在文件的完全路径,以及文件名

__LINE__     代码现处于哪一行(行号)

__DATE__    获取写代码的日期

__TIME__     获取写代码的时间

__FUCTION__     代码存在的函数

__STDC__   遵守标准C,其值为1,否则未定义

预处理指令

#define、#pragma....等以#开头的都是预处理指令,可以定义宏(无参宏,就是定义一个符号,等待替换exp:#define MAX100,再执行程序的之前会将代码中的MAX替换成100,当然一个通过定义一个代码段、表达式为一个特定的符号,去替换)

#define MAX 100
#define reg regiest
#define do_forever for(;;)
#define CASE break;case//这里有个默认规定,定义宏的时候这些符号一般采用大写

在这里的要注意一般不要定义标识符时候,在最后加上语句结束标志“;”,避免替换的时候,造成错误,或者无故的增加运算开销(这里指的是空语句)

#include 
#define MAX 100;
int main()
{ 
   int a = MAX;
   //这里经过预编译之后会变成int a = 100;;  语法上没什么问题,但多了一句空语句,增加了运算开销,而 //有的时候替换的位置并不一定是语句末尾,这样的情况在预处理替换之后会造成错误,所以建议不要再定义宏的 
//时候,在最后加“;”
   printf("%d",a);//100
   return 0;
}

#define也允许把参数定义到文本中,定义有参宏的时候,可以带参

#define name(parament-list) stuff 其中的paramet是用逗号隔开的符号表,类似于函数的参数,而这些符号可能出现在stuff中

#include 
#define ADD(x,y) x+y
#define MUL(x,y) x*y
//define MUL(x,y) (x)*(y)
int main()
{
   int a;
   a=ADD(1,2);
   //a=1+2;再替换的时候将会把参数先传过去,然后再替换到相应位置

   //有的时候要注意的在宏传参的时候的这种情况
   int add=0;
   add=MUL(1+2,5+2);//你一定会想add=21
   //但其实是这样替换的add=1+2*5+2=13所以遇到这样的情况最好在定义宏的时候在参数的后面加上括号
   return 0;
}

而在字符串里的相应符号不会被替换 

#和##应用

#可以将一个字符(宏的参数)插入到字符串中

#include 
//#define PRINT(X) printf("the value of X is:%dn",X)
//int main()
//{
//	int a = 20;
//	int b = 30;
//	//我们要实现的是通过我们传过去的宏参数,打印相对应的值,就是传a的时候就在屏幕上打印the value of a is:传b的时候
//	//就是the value of b is:
//	PRINT(a);
//	//the value of X is:20
//	PRINT(b);
//	//the value of X is:30
//	//这样不合我们的意愿
//
//	return 0;
//}
#define PRINT(X) printf("the value of "#X " is:%dn",X)
int main()
{
	printf("hello ""worldn");
	//照样可以在屏幕上打印   hello world,按照这个原理,就是在printf这个指令中可以将一个字符串分成几个单另的字符串照常输出
	int a = 20;
	int b = 30;
	//这个#可以将一个字符加入到字符串中
	PRINT(a);
	//the value of a is:20
	PRINT(b);
	//the value of b is:30
	

	return 0;
}

##的应用:这个符号可以将两个分离的符号合并成一符号

#include 
#define CAT(x,y) x##y
int main()
{
	int goodboy = 1;
	printf("%dn", goodboy);//1
	printf("%dn",CAT(good,boy));//1
	return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346754.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号