[CSDN]C语言中的宏定义

原文链接:C语言之宏详解(超级详细!)_c语言宏-CSDN博客

目录

一、用宏前须知-#define相关知识

大致结构:

对预定义符号的补充:

二、用#define定义宏

什么是宏?

#define的替换规则:

三、常用的宏定义

1、宏定义常量

2、定义一个宏语句

3、宏定义函数

宏与函数的对比:

4、#和## 分别字符串化和将两个符号连接成一个符号

#字符串化

##将两个符号连接成一个符号

四、与宏相关的作用符号

1、换行符 ‘\’

2、取消宏定义#undef

五、命名约定


一、用宏前须知-#define相关知识

大致结构:

`

1.  #define    name    stuff
    

3.           自定义名    内容
    

`


_ 栗子:_

`

1.  #define OP 256
    
2.  #define YU "youarewelcome"
    
3.  #define S(r) (r*r)
    
4.  #define REG register          //为 register这个关键字,创建一个简短的名字
    
5.  #define PRINT printf("file:%s line:%d\n", __FILE__, __LINE__)//__FILE__,__LINE__这是个啥?别急后面有补充!
    

7.  #include<stdio.h>
    
8.  int main()
    
9.  {
    
10.  	printf("%d \n", OP);
    
11.  	printf("%s \n",YU);
    
12.  	printf("%d \n", S(6));
    
13.  	PRINT;
    
14.  	return 0;
    
15.  }
    

`


     ![](https://img-blog.csdnimg.cn/89f17cac79aa479c93a8ddd213d7de47.png)

对预定义符号的补充:

`

1.  __FILE__      //进行编译的源文件 
    
2.  __LINE__     //文件当前的行号 
    
3.  __DATE__    //文件被编译的日期 
    
4.  __TIME__    //文件被编译的时间 
    
5.  __STDC__    //如果编译器遵循ANSI C,其值为1,否则未定义
    

`



二、用#define定义宏

什么是宏?

宏可以看作为一些命令的集合。它是一种预处理器指令,在预编译阶段将宏名替换为后面的替换体。

    而#define可以用来定义宏:

    #define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。

    宏的声明方式:
`

1.    #define name( parament-list ) stuff
    
2.  //其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中
    

`


    _栗子:_

    实现一个开平方的宏        
`

1.  #define SQ(x) x*x
    

3.  printf("%d \n", SQ(7));
    

`


    **他的实际执行结构为7\*7->即为49**

    还是用这个我们刚刚定义的宏

    我们执行下面这段代码:       
`

1.  int a=6;
    

3.  printf("%d \n", SQ(6+1));
    

`


    他的实际执行结构为6+1\*6+1->即为13

这说明了什么?这印证了上面所说的_宏是把参数替换到文本中_,也就是宏直接吧6+1替换掉了x直接带入了后面的表达式当中了!

    对此,根据我们原来的用意。这时我们可以用括号来解决这个问题:
`#define SQ(x) (x)*(x)`


    这给了我们一个提醒:我们**在用宏时最好多用括号,以此来避免不必要的错误!**

再看个_栗子:_

`

1.  #define DOUBLE(x) (x) + (x) 
    
2.  int a = 5; 
    
3.  printf("%d\n" ,10 * DOUBLE(a));
    

`


    在这个例子中我们对这个宏使用了括号,乍一看这个例子输出的值像是100

    但是实际呢?上图!

  ![](https://img-blog.csdnimg.cn/4f1ee44ddc734af2b23e8beb920b2002.png)

来看看实际它怎么执行的,它执行替换操作实际上为:

`printf ("%d\n",10 * (5) + (5));`


** 因此我们说定义宏要多用括号!**

`#define DOUBLE( x)   ( ( x ) + ( x ) )`


    改成这样就能实现想要的效果啦!

**** #define的替换规则:****

** 在程序中扩展#define** 定义符号和宏时,需要涉及几个步骤:

1. 在调用宏时,首先对参数进行检查,看看是否包含任何由 #define 定义的符号。如果是,它们首先被替换。

2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。

3. 最后,再次对结果文件进行扫描,看看它是否包含任何由 #define 定义的符号。如果是,就重复上 述处理过程。

** 注意:**

1. 宏参数和 #define 定义中可以出现其他 #define 定义的符号。但是对于宏,不能出现递归。

2. 当预处理器搜索 #define 定义的符号的时候,字符串常量的内容并不被搜索。


三、常用的宏定义

1、宏定义常量

     定义诸如:字符串、整形数、浮点型数等等的常量.

_ 栗子:_

`

1.  #define AO 114514
    
2.  #define NTR "我可太喜欢了"
    
3.  #define KK 3.14
    
4.  #include<stdio.h>
    
5.  int main()
    
6.  {
    
7.  	printf("%d %s %f", AO, NTR, KK);
    
8.  	return 0;
    
9.  }
    

`


   ![](https://img-blog.csdnimg.cn/9c7a4a8d7cd2420aad7ce40ac2a1965b.png)

2、定义一个宏语句

_ 栗子:_

`

1.  #include<stdio.h>
    
2.  #define PFINT printf("hello world!\n");
    
3.  int main()
    
4.  {
    
5.  	PFINT///预处理时会被替换为 printf("hello world!\n");
    
6.  	return 0;
    
7.  }
    

`



3、宏定义函数

    宏可以接受参数,类似于真正的函数一样。具体的接受参数方法与函数差不多,只不过不用指定函数类型,这也是宏定义函数的一个优势!比如:当我定义了一个函数有时要传整形,有时要传浮点型,函数可能要根据类型来多定义几个,而宏只需要一个就行了!

_ 栗子1:_

`

1.  #define MAX(a, b) ((a)>(b)?(a):(b))
    
2.  #include<stdio.h>
    

4.  int main()
    
5.  {
    
6.  	printf("%d", MAX(114, 514));
    
7.  	return 0;
    
8.  }
    

`


   ![](https://img-blog.csdnimg.cn/e6bb10ae60e14b209a9577ea91fc7aab.png)

_ 栗子2:_

`1.  #define MALLOC(num, type)\ 
    
2.  (type *)malloc(num * sizeof(type)) //这和\是干啥的?详见地四大点\的作用
    
3.  ... 
    
4.  //使用 
    
5.  MALLOC(10, int);//类型作为参数 
    
6.  //预处理器替换之后: 
    
7.  (int *)malloc(10 * sizeof(int));` 


    这个例子中,_**函数是做不到跟宏相同的效果的**_,所以说为啥有了函数我们还要定义宏呢?这个就是一个很明显的例子。

宏与函数的对比:


4、#和## 分别字符串化将两个符号连接成一个符号****

******#**字符串化
    这个很好理解看看例子就会了!

_ 栗子:_

`

1.  #define STR(exp) printf("%s\n",#exp);
    
2.  #include<stdio.h>
    
3.  int main()
    
4.  {
    
5.  	STR(for fun)
    
6.  	return 0;
    
7.  }
    

`


  ![](https://img-blog.csdnimg.cn/8dd7d77c12654144af940a780c11e68e.png)

##将两个符号连接成一个符号
    ##可以把位于它两边的符号合成一个符号。 它允许宏定义从分离的文本片段创建标识符。

_    栗子:_
`

1.  #include<stdio.h>
    
2.  #define ADD_TO(num, value) num##value
    

5.  int main()
    
6.  {
    
7.  	int a = ADD_TO(114, 514);
    
8.  	printf("%d \n", a);
    
9.  	return 0;
    
10.  }
    

`


   ![](https://img-blog.csdnimg.cn/2e2970b5b17d438c8982a7689f403ca6.png)

四、与宏相关的作用符号

1、换行符 ‘\’

    在每行末尾(除了最后一行)加上"\\",**代表换行的意思**。这个目的是为了不让代码冗余,如果代码都挤在一段,代码就不美观,可读性不好。

   _ 栗子:_
`

1.  #include<stdio.h>
    
2.  #define PFINT printf("hello world!\n");\
    
3.  			  printf("goodbye world!\n");
    
4.  #define NUM 1,\
    
5.  			2,\
    
6.  			3
    
7.  int main()
    
8.  {
    
9.  	PFINT
    
10.  	int x[] = { NUM };//->int x[] = { 1,2,3 };
    
11.  	printf("%d %d %d \n", x[0], x[1], x[2]);
    
12.  	return 0;
    
13.  }
    

`


   ![](https://img-blog.csdnimg.cn/c6e7d9c1eef74ed68d06b3cc113a7f69.png)

2、取消宏定义#undef

    这条指令用于移除一个宏定义。        
`

1.  #define SORT 1000
    
2.  #undef SORT
    

`


** 在#undef之后****SORT就相当于没有定义,失效了**。再使用则会报错!


五、命名约定

    细心的朋友可能发现了!我在**定义宏时用的都是大写的字母**来作为它自定义的名字!

    这是因为这有一个默认的命名约定:

    一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。

    那我们平时的一个习惯是:

   _ **把宏名全部大写**_

    _**函数名不要全部大写                                     **_

** 感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!**

文章知识点与官方知识档案匹配,可进一步学习相关知识

C技能树首页概览196799 人正在系统学习中

学习交流|经验分享|交个朋友

微信名片