程序环境和预处理

目录

一、 程序的翻译环境和执行环境

1.1 翻译环境

 1.2  编译的几个阶段

1.3 执行环境

 二、宏

2.1 宏的申明方式

 2.2 #和##在宏中的特殊使用

2.3  #undef NAME取消宏定义

三、条件编译指令

3.1 #if.......#endif

3.2 #if.......#elif.......#else.......#endif条件定义判断

四、头文件被包含的方式


一、 程序的翻译环境和执行环境

C语言的实现存在两个不同的环境

1、翻译环境:源代码被转换为可执行的机器指令

2、执行环境:用于实际执行代码

1.1 翻译环境

每个源文件通过编译过程分别转换成目标代码(object code);每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序;链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

 1.2  编译的几个阶段

1.3 执行环境

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

 二、宏

2.1 宏的申明方式

#define name( parament-list ) stuff

参数列表的左括号必须与name紧邻。
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

宏在定义时尽量不要省略括号,否则会影响运算过程中的优先级。

举例:

#include<stdio.h>
#define DOUBLE(x) ((x)*(x))
int main()
{
	
	int ret = DOUBLE(3 + 1);//ret=((3+1)*(3+1))
	printf("%d", ret);
	return 0;		
}

部分已定义的宏: 

__FILE__    :源文件所在的路径地址

__LINE__    :代码当前的行号

__DATE__   :编译的日期

__TIME__    :编译的时间

__STDC__   :如果编译器遵循ANSI C标准,其值为1,否则未定义.visual studio是没有定义__STDC__的

#include<stdio.h>
int main()
{
	FILE* pf = fopen("log.txt", "w");//写一个日志文件
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
		fprintf(pf, "file:%s,line=%d,date=%s,time=%s,i=%d\n", __FILE__, __LINE__, __DATE__, __TIME__, i);
	fclose(pf);
	pf = NULL;
	return 0;
}

 

 2.2 #和##在宏中的特殊使用

在宏中使用 # ,可以把一个宏参数变成对应的字符串

#include<stdio.h>
#define PRINT(N) printf("the value of "#N" is %d\n",N)//#N相当于“N”,这时参数就变成了字符
int main()
{
	
	int a = 10;
	PRINT(a);
	int b = 20;
	PRINT(b);
	return 0;		
}
#include<stdio.h>
#define PRINT(N,FORMAT) printf("the value of "#N" is "FORMAT"\n",N)
int main()
{
	
	int a = 10;
	int b = 20;

	PRINT(a, "%d");//%d的双引号不能丢
	PRINT(b, "%d");
	return 0;		
}

 注意FORMAT如果在双引号内,则相当于字符

 ##可以把位于它两边的符号合成一个符号,起联合作用

#include<stdio.h>
#define CONNET(A,B) A##B
int main()
{
	int GOTNUM=100;
	printf("%d", CONNET(GOT, NUM));
	return 0;		
}

2.3  #undef NAME取消宏定义

#undef NAME:这条指令用于移除一个宏定义。

#include<stdio.h>
#define M 10
int main()
{
	printf("%d\n", M);
#undef M
	printf("%d\n", M);//解除M的定义后,这里M都会报错,提示未定义M
	return 0;		
}

三、条件编译指令

3.1 #if.......#endif

如果定义条件成立,则执行中间指令;否则不执行。

其中定义可以写成#ifdef/#if  defined;未定义可写成#ifndef/#if !defined。举例子:

#include<stdio.h>
#define M
int main()
{
	int i = 0;
	int arr[5] = { 0 };
	for (i = 0; i < 5; i++)
	{
		arr[i] = i;
//#ifdef M
//		printf("%d ", arr[i]);//定义了M,则打印arr[i]
//#endif
#if defined M
		printf("%d ", arr[i]);//两种写法均可
#endif
	}

	return 0;
}
#include<stdio.h>
int main()
{
	int i = 0;
	int arr[5] = { 0 };
	for (i = 0; i < 5; i++)
	{
		arr[i] = i;
#ifndef M
		printf("%d ", arr[i]);//定义了M,则打印arr[i]
#endif
//#if !defined M
//		printf("%d ", arr[i]);//两种写法均可
//#endif
	}

	return 0;
}

3.2 #if.......#elif.......#else.......#endif条件定义判断

#include<stdio.h>
#define M 10
int main()
{
#if M<5
	printf("a");
#elif M==5
	printf("b");
#else
	printf("c");//结果打印C
#endif
   return 0;
}

四、头文件被包含的方式

#include "filename"

查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。如果找不到就提示编译错误。

#include <filename.h>

查找策略:查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。

虽然库文件也可以用“ ”包含,但是如果想查找效率高,最好用《》包含。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值