1、C语言中的宏定义

  #define是预处理器处理的单元实体之—

  #define定义的宏可以出现在程序的任意位置

  #define定义之后的代码都可以使用这个宏

2、定义宏常量

  #define定义的宏常量可以直接使用

  #define定义的宏常量本质为字面量

下面的宏常量定义正确吗?

 #define ERROR -1   
  
#define PATHl "D:\test\test.c"   
  
#define PATH2 D:\test\test.c   
  
#define PATH3 D:\test\   
test.c  

3、实例分析

宏定义分析     21-1.c

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

预处理器不会进行语法检查只是简单的文本替换,即这些宏定义都正确!!但编译器会报错!!

4、宏定义表达式

  #define表达式的使用类似函数调用

  #define表达式可以比函数更强大

  #define表达式比函数更容易出错

下面的宏表达式定义正确吗?

  

 #define _SUM_(a, b) (a) + (b)   
  
#define _MIN_(a, b) ((a) < (b) ? (a) : (b))   
  
#define _DIM_(a) sizeof(a)/sizeof(*a)  

5、实例分析

宏表达式分析     21-2.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 = ;  
    int b = ;  
    int c[] = {};  
  
    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 ;  
}  

6、宏表达式与函数的对比

  宏表达式被预处理器处理,编译器不知道宏表达式的存在

  宏表达式用“实参“完全替代形参,不进行任何运算

  宏表达式没有任何的“调用”开销

  宏表达式中不能出现递归定义

 #define _SUM_(n) ((n > 0) ? (_SUM_(n-1) + n): 0) //error

 int s = _SUM_();

7、有趣的问题

宏定义的常量或表达式是否有作用域限制?

下面的程序合法吗?

 void def()   
{  
    #define PI 3.1415926   
    #define AREA(r) r*r*PI  
}  
  
double area(double r)   
{  
    return AREA(r);  
}   

8、实例分析

宏的作用域分析     21-3.c

 #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();  
  
    printf("PI = %f\n", PI);  
    printf("d = 5; a = %f\n", r);  
      
    return ;  
}  

9、强大的内置宏

  
  __LINE__ 表示当前行号,整型值
  __FILE__ 表示当前文件名,字符串类型
  __DATE__ 编译的日期,字符串类型
  __TIME__ 编译的时间,字符串类型
  __STDC__ 预定义的宏

10、实例分析

宏使用综合示例     21-4.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 = ;  
    int* p = MALLOC(int, );  
      
    LOG("Begin to run main code...");  
      
    FOREACH(x, )  
    BEGIN  
        p[x] = x;  
    END  
      
    FOREACH(x, )  
    BEGIN  
        printf("%d\n", p[x]);  
    END  
      
    FREE(p);  
      
    LOG("End");  
      
    return ;  
}  

11、小结

  预处理器直接对宏进行文本替换

  宏使用时的参数不会进行求值和运算

  预处理器不会对宏定义进行语法检查

  宏定义时出现的语法错误只能被编译器检测

  宏定义的效率高于函数调用

  宏的使用会带来—定的副作用

C语言-宏定义与使用分析的更多相关文章

  1. C 语言宏定义

    C 语言宏定义1.例子如下: #define PRINT_STR(s) printf("%s",s.c_str()) string str = "abcd"; ...

  2. 将C语言宏定义数值转换成字符串!

    将C语言宏定义转换成字符串! 摘自:https://blog.csdn.net/happen23/article/details/50602667 2016年01月28日 19:15:47 六个九十度 ...

  3. C语言 宏定义之可变参数

    可变参数宏定义 C99编译器标准允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏.可变参数宏就像下面这个样子: #define dbgprint(. ...

  4. c语言宏定义

    一. #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能理解该命令的本质,总是在此处产生一些困惑,在编程时 ...

  5. C语言宏定义#define用法

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用 ...

  6. C 语言宏定义函数编写时 do-while 的妙用和一些注意事项

    在 C 语言中,我们都知道可以用宏定义来编写函数,一般称为宏函数.如果一个宏函数比较复杂,那么在编写这样的宏函数是有一定技巧和注意事项的.文章给出一些我认为值得关注的地方,以及一些注意事项(个人建议) ...

  7. C语言宏定义时#(井号)和##(双井号)的用法1

    #在英语里面叫做 pound 在C语言的宏定义中,一个#表示字符串化:两个#代表concatenate 举例如下: #include <iostream> void quit_comman ...

  8. C语言宏定义时#(井号)和##(双井号)的用法

    C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念).下面对常遇到的宏的使用问题做了简单总结. 关于#和## 在C语言的宏中,#的功能是将其后面 ...

  9. C语言宏定义相关

    写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等.下面列举一些成熟软件中常用得宏定义......1,防止一个头文件被重复包含#ifndef COMDEF_H# ...

随机推荐

  1. c++ 浮点数小数位

    . double f = 3.123456789; . cout<<f<<endl; // 输出3.12346 (包含整数和小数,且四舍五入) . cout<<se ...

  2. 【sklearn文本特征提取】词袋模型/稀疏表示/停用词/TF-IDF模型

    1. 词袋模型 (Bag of Words, BOW) 文本分析是机器学习算法的一个主要应用领域.然而,原始数据的这些符号序列不能直接提供给算法进行训练,因为大多数算法期望的是固定大小的数字特征向量, ...

  3. Python3标准库:array数组

    1. array数组 array模块定义了一个序列数据结构,看起来与list很相似,只不过所有成员都必须是相同的基本类型.支持的类型包括所有数值类型或其他固定大小的基本类型(如字节). 代码 类型 最 ...

  4. javascript当中onload用法

    7)onload onload就是等页面加载完后才执行. 例 3.7.1 <HEAD> <meta http-equiv="content-type" conte ...

  5. java课程学习心得

    首先是枚举,使用enum关键字创建,如:enum {SMALL,MEDIUM,LARGE}之后便可定义Size 的类型变量,并复制为{SMALL,MEDIUM,LARGE};其中一个,注意赋值方法,x ...

  6. C#Linq的10个练习

    1.LINQ的两种语法 LINQ查询时有两种语法可供选择:查询表达式(Query Expression)和方法语法(Fluent Syntax). .NET公共语言运行库(CLR)并不具有查询表达式的 ...

  7. win10中安装与配置maven

    原文链接:https://www.cnblogs.com/wkrbky/p/6350334.html Maven安装配置(Windows10) 想要安装 Apache Maven 在Windows 系 ...

  8. 【Vue2.x笔记1】数据响应式原理

    1.Object.defineProperty Vue2.x 使用Object.defineProperty 将 Vue 实例中的data对象全部转为getter/setter.在内部让 Vue 能够 ...

  9. os常用讲解

    os.mkdir()创建单个不存在的空目录,无法创建多个或者已经存在的含有文件的同名目录 os.makedirs() 能够递归创建多个目录,如果目录已经存在即使都是空的或者目录已经存在且含有文件,则引 ...

  10. 统一身份认证服务IdentityServer4实践

    导读 当企业的应用系统逐渐增多后,每个系统单独管理各自的用户数据容易形成信息孤岛,分散的用户管理模式阻碍了企业应用向平台化演进.当企业的业务发展到一定规模,构建统一的标准化账户管理体系将是必不可少的, ...