预处理详解

发布时间:2024年01月18日

1.预定义符号?

C语言设置了一些预定义符号,可以直接使用,预定义符号也是预处理期间处理的(-代表下划线)

#include<stdio.h>
int main()
{
	printf("%s\n", __FILE__);//生成此文件的位置信息
	printf("%d\n", __LINE__);//生成此行的行号
	printf("%s\n",__DATE__);//生成被编译的日期
	printf("%s\n", __TIME__);//生成被编译的时间
	//printf("%d\n", __STDC__);//如果编译器遵循ANSIC,其值为1,否则未定义,VS不支持
	return 0;
}

?2.#define定义常量

基本语法:(有时可以简化代码,但可读性会变差)

#define name stuff

例如:

#define Case break;case
int main()
{
	int n = 0;
	switch (n)
	{
	case 1:
		Case 2 :
			Case 3 :
			Case 4 :
			break;
	}
	return 0;
}

3.#define定义宏?

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

#define name(parament-list) stuff

其中parament-list是一个由逗号隔开的符号表,它们可能出现在stuff中

注:参数列表的左括号必须与name紧邻,如果两者这件有空白存在,参数列表就会被解释为suffer的一部分

4.宏替换的规则

在程序中扩展#define定义符号和宏时, 需要涉及几个步骤。

  1. 在调用宏时, 首先对参数进行检查,看看是否包含任何由#define定义的符号。 如果是,它们首先被替换。
  2. ?替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
  3. 最后, 再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。 如果是,就重复上述处理过程。

?注意:

  1. 宏参数和#define 定义中可以出现其他#define定义的符号。 但是对于宏, 不能出现递归。
  2. 当预处理器搜索#define定义的符号的时候, 字符串常量的内容并不被搜索。

5.宏函数的对比

宏通常被用于执行简单的运算

比如两个数中找出较大的一个时,写成如下方式更好一些:

#define Max(a,b) ((a)>(b)?(a):(b))

那为什么不用函数来完成这个任务?

宏有时候可以做函数做不到的事情。 比如:宏的参数可以出现类型,但是函数做不到。

  1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。 所以宏比函数在程序的规模和速度方面更胜一筹。
  2. 更为重要的是函数的参数必须声明为特定的类型。 所以函数只能在类型合适的表达式上使用。 反之这个宏怎可以适用于整形、 长整型、浮点型等可以用于>来比较的类型。宏的参数是类型无关的。?

和函数相比宏的劣势:

  1. 每次使用宏的时候, 一份宏定义的代码将插入到程序中。除非宏比较短, 否则可能大幅度增加程序的长度。
  2. 宏是没法调试的。
  3. 宏由于类型无关, 也就不够严谨。
  4. 宏可能会带来运算符优先级的问题, 导致程容易出现错。
    ?

6.#和##

#运算符将宏的一个参数转换为字符串字面量。

它仅允许出现在带参数的宏的替换列表中。#运算符所执行的操作可以理解为“字符串化”

当我们有一个变量int a = 10; 的时候, 我们想打印出:the value of a is 10

就可以写:

#define PRINT(n) printf("the value of "#n" is %d",n);
当我们按照下面的方式调用的时候:

PRINT(a);//当我们把a替换到宏的体内时, 就出现了#a, 而#a就是转换为"a", 时一个字符串代码就会被预处理为:
printf("the value of ""a"" is %d",a);

?##运算符
## 可以把位于它两边的符号合成一个符号, 它允许宏定义从分离的文本片段创建标识符。 ##被称为记号粘合,这样的连接必须产生一个合法的标识符。 否则其结果就是未定义的。

这里我们想想, 写一个函数求2个数的较大值的时候, 不同的数据类型就得写不同的函数。比如:

int int_max(int x, int y)
{
	return x > y ? x : y;
}
float float_max(float x, float y)
{
	return x > y ? x : y;
}

用宏定义写:

#define MAX(type)\
type type##_max(type)\
{\
	return (x>y?x:y);\
}

7.命令行定义(了解)

许多C的编译器提供了一种能力, 允许在命令行中定义符号。 用于启动编译过程。
例如: 当我们根据同一个源文件要编译出一个程序的不同版本的时候, 这个特性有点用处。 (假定某个程序中声明了一个某个长度的数组, 如果机器内存有限, 我们需要一个很小的数组,但是另外一个机器内存大些, 我们需要一个数组能够大些。)

编译指令:(gcc环境)

gcc -D ARRAY_SIZE=10 program.c

8.条件编译(重要)

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。
调试性的代码,删除可惜, 保留又碍事, 所以我们可以选择性的编译。

常见的条件编译指令:

1.单分支的条件编译
#if 常量表达式
//...
#endif//常量表达式由预处理器求值
2.多分支的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
3.判断是否被定义
#if define(symbol)
#ifdef symbol

#if !define(symbol)
#ifndef symbol
4.嵌套指令
#if define(...)
	#ifdef...
		...
	#endif
	#ifdef(...)
		...
	#endif
#elif ...
	#ifdef(...)
		...
	#endif
#endif

?

文章来源:https://blog.csdn.net/2301_80002696/article/details/135662813
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。