程序的编译与预处理

  • Post author:
  • Post category:其他


1. 程序的编译与链接

平时我们写的都是后缀为.c的文件,经过编译后生成目标文件(.obj),最后通过链接后生成可执行程序(.exe)

源文件        ——>        编译        ——>        链接        ——>        可执行程序

而编译部分又包括: 预处理、编译、汇编

预处理:头文件的包含、#define定义符号的替换、注释的删除

编译:把C语言代码翻译成汇编代码

汇编:把汇编指令翻译成二进制指令

2. 预定义符号

__FILE__

__LINE__

__DATE__

__TIME__

__STDC__
//进行编译的源文件

//文件当前的行号

//文件被编译的日期

//文件被编译的时间

//如果编译器遵循ANSI C,其值为1,否则未定义
int main()
{
	printf("%s\n", __FILE__);//进行编译的源文件
	printf("%ld\n", __LINE__); //文件当前的行号
	printf("%s\n", __DATE__); //文件被编译的日期
	printf("%s\n", __TIME__); //文件被编译的时间
	printf("%d\n", __STDC__); //如果编译器遵循ANSI C,其值为1,否则未定义

	return 0;
}


因为__STDC__未定义,所以编译器比遵循标准C规定

注释掉之后:

3. #define

3.1 #define定义标识符

用define定义的标识符会在预处理阶段被替换成它所表示的常量,比如:

#define M 100

int main()
{
	int m = 0;
	m = M;//在预处理阶段就替换成了 m = 100; 
	printf("%d", m);

	return 0;
}

3.2 #define定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏

例如:

#define SQUARE(M) M*M

int main()
{
	printf("%d", SQUARE(10));

	return 0;
}


但只是这样并不严谨,实现宏的定义圆括号在大多时候都是不可缺少的

#define DOUBLE(M) M+M

int main()
{
	//我们期望的结果是5*20

	printf("%d", 5* DOUBLE(10));

    //但实际结果是60
    //因为代码被替换成了 5 * 10 + 10

	return 0;
}

#define DOUBLE(M) ((M)+(M))
//加括号后就会得到我们期望的结果了

int main()
{
	printf("%d", 5* DOUBLE(10));
	//			 5* ((10) + (10))

	return 0;
}

乍看上去宏和函数好像一样

实际上他们有许多不同:

1.从执行速度上宏的优势更明显,因为函数还有调用花费时间

2.从参数限制的角度看宏更好用,因为它不规定参数必须是什么类型

3.从调试的角度看函数更好用,因为宏在预处理的时候就被替换了,不便调试,而函数可以一步一步的调试

4.从代码长度的角度看函数更好用,因为函数只写一次定义,可以直接调用,而宏每次都要替换,会使程序的长读大幅度增长

5.函数可以递归,宏不可以递归

4.条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃就可以用条件编译指令。

比如说:

调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译

#define DEBUG 

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;

//如果定义了DEBUG就执行下面的代码
#ifdef DEBUG
		printf("%d ", arr[i]);
//条件编译结束标志
#endif

	}

	return 0;
}

//#define DEBUG 

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;

//如果定义了DEBUG就执行下面的代码
#ifdef DEBUG
		printf("%d ", arr[i]);
//条件编译结束标志
#endif

	}

	return 0;
}

//#define DEBUG 

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;

//如果没有定义DEBUG就执行下面的代码
#ifndef DEBUG
		printf("%d ", arr[i]);
//条件编译结束标志
#endif

	}

	return 0;
}

常见的条件编译还有:

#if   常量表达式

#endif

例如:

#define M 1
int main()
{
#if M
	printf("YES");
#endif

	return 0;
}

还有多分支的条件编译:

#if 常量表达式

#elif 常量表达式

#endif

例如:

#define M 0
#define N 1

int main()
{
#if M
	printf("YES");
#elif N
	printf("NO");
#endif

	return 0;
}



版权声明:本文为WKBcm原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。