温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C之宏定义(十九)

发布时间:2020-07-06 12:01:11 来源:网络 阅读:1185 作者:上帝之子521 栏目:编程语言

        我们在 C 语言中经常会用到宏定义,那么我们今天就对宏做个简单的介绍。#define 是预处理期处理的单元实体之一;它定义的宏可以出现在程序的任意位置;它定义之后的代码都可以使用这个宏。

        #define 定义的宏常量可以直接使用,其本质为字面量。它与 const 定义的常量的区别是:const 修饰的常量本质是变量,占用内存;而字面量是不占用内存的。我们来看看下面这几个宏常量定义是否正确

#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;     char* p2 = PATH2;     char* p3 = PATH3; }

        我们分析下,前两个肯定正确,第三种猜测是正确的,因为宏定义只是简单的替换。第四种也是正确的,最后的 \ 我们看成是前面介绍的接续符。我们来单步编译下,看看结果

C之宏定义(十九)

        我们看到单步编译的时候,它没出错。就是进行简单的替换,我们再加上头文件,进行编译。结果如下

C之宏定义(十九)

        我们看到编译出错了,因为宏只是被预处理期处理,预处理期不会去检查语法,所以会单步编译通过。所以在编译检查语法的时候出错了。我们下来看个示例代码,代码如下

#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; }

        我们分析,第14行返回相加和,因而第19行打印 3;第15行返回加和的平方,因而第20行打印 9;第16行返回最小值,因而第21行打印 1;第17行返回的是数组的个数,所以第22行打印 4。我们看看编译结果

C之宏定义(十九)

        结果跟我们分析的不太一样,中间两个不一样。我们来单步编译下,看看是什么样的

C之宏定义(十九)

        我们看到它的 main 函数是这样的,因而我们分析的是错的。那么在这块我们是忽略了宏表达式和函数的差异,那么宏表达式有哪些特性呢?如下:a> 宏表达式被预处理器处理,编译器不知道宏表达式的存在;b> 宏表达式用“实参”完全代替形参,不进行任何运算;c> 宏表达式没有任何的“调用”开销;d> 宏表达式中不能出现递归定义,如:#define _SUM_(n) ((n > 0) ? (_SUM_(n-1) + n) : 0); int s = _SUM_(5);

        那么我们来思考下:宏定义的常量或表达式是否有作用域限制?我们来看看下面的代码

#include <stdio.h> void def() {     #define PI 3.1415926     #define AREA(r) r * r * PI } double area(double r) {     return AREA(r); } int main() {     double r = area(5);     printf("PI = %f\n", PI);     printf("d = 5; a = %f\n", r);          return 0; }

        那么在 def 函数里定义的宏能否在 area 函数里使用呢?也就是说宏定义的作用域是否是具有函数作用域呢,我们来看看编译结果

C之宏定义(十九)

        它并没有报错,而是成功运行。在这里我们注释掉头文件和打印语句,我们来单步编译下,看看函数里是怎样的?

C之宏定义(十九)

        明显在 area 函数里直接展开宏,也就是说宏定义的常量没有作用域的限制。我们再来看看 C 语言中强大的内置宏

C之宏定义(十九)

        我们利用内置宏编写析下面的代码,代码如下:

#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; }

        我们在第4行定义 MALLOC 为申请堆空间并用指针来存储地址,第6行利用之前学习的逗号表达式来释放申请到的指针。第8行则是利用内置宏定义 LOG 打印信息,第10-12行分别定义 for 循环和{ }。我们来看看编译后打印的结果

C之宏定义(十九)

        我们看到内置宏是如此的强大,目前在 C 语言中是利用函数办不到来打印文件名和行数信息的。通过对宏定义的学习,总结如下:1、预处理期直接对宏进行文本替换,宏使用时的参数不会进行求值和运算;2、预处理期不会对宏定义进行语法检查,宏定义出现的缘分错误只能被编译器检测;3、宏定义的效率高于函数调用但会带来一定的副作用。后面我们会继续对 C 语言的学习。


         欢迎大家一起来学习 C 语言,可以加我QQ:243343083

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI