文章目录
1 宏定义
1.1 宏定义的基本概念
宏定义的基本概念:
- #define是预处理器处理的单元实体之一。
- #define定义的宏可以出现在程序的任意位置。
- #define定义之后的代码都可以使用这个宏。
- 预处理器直接对宏进行文本替换。
- 预处理器不会对宏定义进行语法检查,宏定义时出现的语法错误只能被编译器检测。
- 宏定义的效率高于函数,但是宏的使用也会带来一定的副作用。
注意: 宏是没有作用域的概念的,作用域是针对函数和变量来说,因为函数和变量是由编译器处理,而宏则是由预处理器进行处理的。
1.2 定义宏常量
我们可以定义宏常量:
- #define定义的宏常量可以直接使用。
- #define定义的宏常量本质为字面量。
#define ERROR -1
#define PATH1 "D:\test\test.c"
#define PATH2 D:\test\test.c
#define PATH3 D:\test\
test.c
int main()
{
int err = ERROR;
char* p1 = PATH1; // OK
char* p2 = PATH2; // 预处理正常,编译error
char* p3 = PATH3; // 预处理正常,编译error
}
1.3 宏定义表达式
我们可以通过宏定义表达式:
- #define表达式的使用类似函数调用
- #define表达式可以比函数更强大
- #define表达式比函数更容易出错
// #include <stdio.h>
#define _SUM_(a, b) (a) + (b)
#define _MIN_(a, b) ((a) < (b) ? (a) : (b))
#define _DIM_(a) sizeof(a)/sizeof(*a)
int main()
{
int a = 1;
int b = 2;
int c[4] = {0};
int s1 = _SUM_(a, b);
int s2 = _SUM_(a, b) * _SUM_(a, b); // 计算结果将出错
int m = _MIN_(a++, b); // 计算结果将出错
int d = _DIM_(c); // 函数比宏强大的地方
// printf("s1 = %d\n", s1);
// printf("s2 = %d\n", s2);
// printf("m = %d\n", m);
// printf("d = %d\n", d);
return 0;
}
1.4 宏表达式与函数的对比
宏表达式和函数的对比:
- 宏表达式被预处理处理,编译器不知道宏表达式的存在。
- 宏表达式用“实参”完全代替形参,不进行任何运算。
- 宏表达式没有任何的“调用开销”。
- 宏表达式中不能出现递归定义。
#define SUM(n) (n > 0 ? SUM(n-1) + n : 0)
int sum = SUM(10);
// 预处理后的结果
int sum = (10 > 0 ? SUM(10 -1) + 10 : 0);
2 内置宏
2.1 强大的内置宏

宏的使用综合示例:
#include <stdio.h>
#include <malloc.h>
#define MALLOC(type, x) (type*)malloc(sizeof(type)*x)
#define FREE(p) (free(p), p=NULL)
#define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s)
#define FOREACH(i, m) for(i=0; i<m; i++)
#define BEGIN {
#define END }
int main()
{
int x = 0;
int* p = MALLOC(int, 5);
LOG("Begin to run main code...");
FOREACH(x, 5)
BEGIN
p[x] = x;
END
FOREACH(x, 5)
BEGIN
printf("%d\n", p[x]);
END
FREE(p);
LOG("End");
return 0;
}
3 不能使用宏定义的情况
3.1 不能使用宏定义注释符号
#define BSC //
#define BMC /*
#define EMC */
BSC my signle-line comment
BMC my multi-line comment EMC
上面的代码编译将出现错误,因为当相应的宏被替换成注释符号后,这个时候预处理期对宏的替换已经处理完毕,这里自然也就出错了(编译错误)。
4 函数与宏分析
4.1 函数与宏的对比分析
| 宏 | 函数 |
|---|---|
| 宏是由预处理器直接替换展开的,编译器不知道宏的存在 | 函数是由编译器直接编译的实体,调用行为由编译器决定 |
| 多次使用宏会导致最终可执行程序的体积增大 | 函数是跳转执行的,内存中只有一份函数体存在 |
| 宏的效率比函数要高,因为是直接展开,无调用开销 | 函数调用时会创建活动记录,效率不如宏 |
| 宏能够接受任何类型的参数,效率高,易出错 | 函数的参数必须是固定类型,效率稍低,不易出错 |
宏的注意点:
- 宏的效率比函数稍高,但是其副作用巨大。
- 宏是文本替换,参数无法进行类型检查。
- 可以用函数完成的功能绝对不用宏。
- 宏的定义中不能出现递归定义。
- 宏可以实现函数不能实现的功能。
宏的副作用:
#include <stdio.h>
#define _ADD_(a, b) a + b
#define _MUL_(a, b) a * b
#define _MIN_(a, b) ((a) < (b) ? (a) : (b))
int main()
{
int i = 1;
int j = 10;
printf("%d\n", _MUL_(_ADD_(1, 2), _ADD_(3, 4)));
printf("%d\n", _MIN_(i++, j));
return 0;
}
4.2 宏的妙用
宏主要有如下妙用:
- 用于生成一些常规性的代码。
- 封装函数,加上类型信息。
#include <stdio.h>
#include <malloc.h>
#define MALLOC(type, x) (type*)malloc(sizeof(type)*x)
#define FREE(p) (free(p), p=NULL)
#define LOG_INT(i) printf("%s = %d\n", #i, i)
#define LOG_CHAR(c) printf("%s = %c\n", #c, c)
#define LOG_FLOAT(f) printf("%s = %f\n", #f, f)
#define LOG_POINTER(p) printf("%s = %p\n", #p, p)
#define LOG_STRING(s) printf("%s = %s\n", #s, s)
#define FOREACH(i, n) while(1) { int i = 0, l = n; for(i=0; i < l; i++)
#define BEGIN {
#define END } break; }
int main()
{
int* pi = MALLOC(int, 5);
char* str = "D.T.Software";
LOG_STRING(str);
LOG_POINTER(pi);
FOREACH(k, 5)
BEGIN
pi[k] = k + 1;
END
FOREACH(n, 5)
BEGIN
int value = pi[n];
LOG_INT(value);
END
FREE(pi);
LOG_POINTER(pi);
return 0;
}
参考资料:
本文深入解析C语言宏定义的使用,包括基本概念、宏常量定义、宏表达式及与函数的区别,同时探讨了宏的潜在问题与妙用,提供丰富的代码示例。
8188

被折叠的 条评论
为什么被折叠?



