宏定义与分析

宏定义与分析:

我们都数值宏定义通过define来定义。#define 定义的变量区别于const等定义变量的方式,其本质时字面量,并不会占用内存空间。

define定义的函数:

define 定义的函数比常规函数定义更加强大,也方便。

#define  sum(a, b) (a)+(b)

#define _MIN_(a,b) ((a) < (b) ? (a) : (b))

#define  _DIM_(a) sizeof(a) / sizeof(*a)

宏定义比常规函数更容易出错:

int a = 1;
int b = 2;
int c[5] = {0};
int s = _SUM_(a,b) * _SUM_(a,b)    // 常规想法是 3*3 = 9,而实际输出为 1+2*1+2 = 5;
int s1 = _DIM_(c)          // 输出数组长度 5

首先我们先讲宏定义的强大的地方,如果按照 “ sizeof(c) / sizeof(int) ”的方式计算数组长度,正常函数是无法计算的,返回的均为1。其原因是数组作为实参传入函数内部,其本质传入的为数组的首地址,所以sizeof(c)为首地址的大小而非数组大小。而宏定义内的数组参数则可以作为正常数组大小来计算,这就是宏定义强大的地方之一。

其次,我们在使用宏定义做复杂的运算时,一定要注意元素符号的优先级,比如上面两个累加和相乘, * 的优先级要高于 + ,所以才会出现1+2*1+2 的情况,最好的方法是用()括起来。

那么相比于定义的add()函数,为什么宏定义会出现这种情况呢?

我们都知道编译器会对代码的逻辑以及语法进行检查,以及后续的计算。而宏定义在编译器编译之前,已经被预处理器进行处理了。这时候预处理器并不知道后面所跟的内容(*_SUM_(a,b)),他只会去处理分析宏定义的逻辑,代码的逻辑语法并不会去分析处理。

宏定义没有任何的“调用”的开销,在实际函数定义中,通常会把实参作为形参来处理。但相比于函数,宏定义并不能实现递归逻辑。

宏定义的常量是否有作用域

// 在一个函数内定义两个宏定义,在另一个函数中使用,这种方法是否是可行的
void def(){
   #define PI 3.1415926
   #define ARR(r)  r*r*PI  
}
double area(double r){
     retrun ARR(r);  
}

我们都知道,函数内部定义的变量的作用域只在函数内,不能被其他函数所调用。而宏定义是在编译前预处理器处理的,所以编译器并不知道宏定义的位置,所以与函数外定义的宏是等同的,但是在实际编程规范里还是要写在文件开头位置。

C语言内置宏:

 

 

 

// 举一个例子 file.c
#define MALLOC(type, n) (type*)malloc(sizeof(type) * n)
#define FREE(p) {free(p), p=NULL}   // 释放p内存,并指向NULL
#define LOG(s)  printf("[%s][%s][%s], %s/n", __DATA__, __FILE__, __LINE__, s)
#define FOREACH(i, n) for(i = 0; i<n; i++)
#define START {
#define END }

int main()
{
   LOG("start to run main");
   int x = 0;
   int *p = MALLOC(int, 5);     // 宏定义可以讲数据类型作为实参传入函数。
   FOREACH(x, 5)
   START
        p[x] = x;
   END   

   FOREACH(x, 5)
   START
        printf("%d", p[x]);
   END

   FREE(p);  
   LOG("stop to run main");   
}
// 输出结果
[Apr  2 2023][test.c][13], start to run main
0
1
2
3
4
[Apr  2 2023][test.c][27], stop to run main
posted @ 2023-04-02 23:17  嵌入式小白—  阅读(178)  评论(0编辑  收藏  举报