1. 主页
  2. 文档
  3. C语言教程
  4. C语言基础教程
  5. C 中关于宏和预处理器的有趣事实

C 中关于宏和预处理器的有趣事实

在 C 程序中,所有以#开头的行都由预处理器处理,预处理器是由编译器调用的特殊程序。我们的意思是说“#”符号用于比程序中的其他语句更早地处理功能,也就是说,这意味着它在运行时或编译时处理一些代码。在一个非常基本的术语中,预处理器采用一个 C 程序并生成另一个没有任何# 的C 程序。

以下是有关 C 中预处理器的一些有趣事实。 

1)当我们使用include 指令时,被包含的头文件(预处理后)的内容被复制到当前文件中。 
尖括号<>指示预处理器在保存所有头文件的标准文件夹中查找。双引号指示预处理器查看当前文件夹(当前目录)。 

2)当我们对常量使用define 时,预处理器生成一个C 程序,其中搜索定义的常量并将匹配的标记替换为给定的表达式。例如在下面的程序中max被定义为 100。

#include <stdio.h>
#define max 100
int main()
{
printf("max is %d", max);
return 0;
}

输出: 

max is 100

3)宏可以采用类似参数的函数,不检查参数的数据类型。例如,以下宏 INCREMENT(x) 可用于任何数据类型的 x。

#include <stdio.h>
#define INCREMENT(x) ++x
int main()
{
char* ptr = "GeeksQuiz";
int x = 10;
printf("%s ", INCREMENT(ptr));
printf("%d", INCREMENT(x));
return 0;
}

输出: 

eeksQuiz  11

4)在宏扩展之前不评估宏参数。例如,考虑以下程序

#include <stdio.h>
#define MULTIPLY(a, b) a* b
int main()
{
// The macro is expanded as 2 + 3 * 3 + 5, not as 5*8
printf("%d", MULTIPLY(2 + 3, 3 + 5));
return 0;
}
// Output: 16

输出: 

16

可以使用以下程序解决之前的问题 

#include <stdio.h>
// here, instead of writing a*a we write (a)*(b)
#define MULTIPLY(a, b) (a) * (b)
int main()
{
// The macro is expanded as (2 + 3) * (3 + 5), as 5*8
printf("%d", MULTIPLY(2 + 3, 3 + 5));
return 0;
}
// This code is contributed by Santanu

输出: 

40

5)传递给宏的令牌可以使用称为令牌粘贴运算符的运算符##进行连接。

#include <stdio.h>
#define merge(a, b) a##b
int main() 
{ 
printf("%d ", merge(12, 34)); 
}

输出: 

1234

6)传递给宏的标记可以通过在它之前使用# 转换为字符串文字。

#include <stdio.h>
#define get(a) #a
int main()
{
printf("%s", get(52cxydh));
}

输出: 

52cxydh

7)宏可以使用’\’ 写成多行。最后一行不需要有“\”。

#include <stdio.h>
#define PRINT(i, limit) \
while (i < limit) { \
printf("52cxydh"); \
i++; \
}
int main()
{
int i = 0;
PRINT(i, 3);
return 0;
}

输出: 

52cxydh 52cxydh 52cxydh

8)应避免使用带参数的宏,因为它们有时会引起问题。内联函数应该是首选,因为内联函数中有类型检查参数评估。从C99开始,C 语言也支持内联函数。 

例如,考虑以下程序。乍一看,输出似乎是 1,但它产生 36 作为输出。

#include <stdio.h>

#define square(x) x* x
int main()
{
// Expanded as 36/6*6
int x = 36 / square(6);
printf("%d", x);
return 0;
}

输出

36

但是我们可以这样写这段代码来得到预期的结果,即 1:

#include <stdio.h>

#define square(x) (x * x)
int main()
{
// Expanded as 36/(6*6)
int x = 36 / square(6);
printf("%d", x);
return 0;
}

输出

1

如果我们使用内联函数,我们会得到预期的输出。此外,可以使用内联函数更正上面第 4 点中给出的程序。

#include <stdio.h>

static inline int square(int x) { return x * x; }
int main()
{
int x = 36 / square(6);
printf("%d", x);
return 0;
}

输出:

1

9)预处理器还支持通常用于条件编译的 if-else 指令。 

int main()
{
#if VERBOSE >= 2
printf("Trace Message");
#endif
}

输出: 

No Output

10)一个头文件可能会被直接或间接包含多次,这会导致重新声明相同变量/函数的问题。为了避免这个问题,使用了诸如definedifdefifndef 之类的指令。 

11) C 代码中有一些标准宏可以用来打印程序文件(__FILE__)、编译日期(__DATE__)、编译时间(__TIME__)和行号(__LINE__)

#include <stdio.h>

int main()
{
printf("Current File :%s\n", __FILE__);
printf("Current Date :%s\n", __DATE__);
printf("Current Time :%s\n", __TIME__);
printf("Line Number :%d\n", __LINE__);
return 0;
}

输出: 

Current File :/usr/share/IDE_PROGRAMS/C/other/081c548d50135ed88cfa0296159b05ca/081c548d50135ed88cfa0296159b05ca.c
Current Date :Sep  4 2019
Current Time :10:17:43
Line Number :8

12)我们可以使用:#undef MACRO_NAME删除已经定义的宏

#include <stdio.h>
#define LIMIT 100
int main()
{
printf("%d", LIMIT);
// removing defined macro LIMIT
#undef LIMIT
// Next line causes error as LIMIT is not defined
printf("%d", LIMIT);
return 0;
}

以下程序正确执行,因为我们在删除先前定义的宏 LIMIT 后已将 LIMIT 声明为整数变量 

#include <stdio.h>
#define LIMIT 1000
int main()
{
printf("%d", LIMIT);
// removing defined macro LIMIT
#undef LIMIT
// Declare LIMIT as integer again
int LIMIT = 1001;
printf("\n%d", LIMIT);
return 0;
}

输出: 

1000
1001

关于宏使用(#undef)的  另一个有趣的事实

#include <stdio.h>
// div function prototype
float div(float, float);
#define div(x, y) x / y

int main()
{
// use of macro div
// Note: %0.2f for taking two decimal value after point
printf("%0.2f", div(10.0, 5.0));
// removing defined macro div
#undef div
// function div is called as macro definition is removed
printf("\n%0.2f", div(10.0, 5.0));
return 0;
}

// div function definition
float div(float x, float y) { return y / x; }

输出: 

2.00
0.50

 

这篇文章对您有用吗? 1