详解C语言中 # 和 ## 的用法

一句话总结功能:
使用#把宏参数变为一个字符串,用##把两个宏参数粘连到一起

##用来连接前后两个参数,拼接符号。可以是符号拼符号,可以是数字拼符号,可以是数字拼数字
#用来对后面的宏参数进行字符串化操作,简单来说就是相当于在宏变量的两边各加上一个双引号使其变成一个字符串
注意,##和#只可用在宏定义中,这只是给编译器看的。(语句体中不可直接用##和#)
功能总结很简单,但实际应用方式却多种多样,可谓非常强大。

一、基础应用:
例1:使用 # ,把一个宏参数变成对应的字符串

#include<stdio.h>

#define PRINT(X) printf("the "#X" value is %d\n",X)

int main()
{
    
    
	int a = 2;

	PRINT(a);

	return 0;
}

输出:

the a value is 2

上面的 PRINT(a) 展开相当于 printf(“the " “a” " value is %d\n”,a)
注意里面有三个字符串,打印的时候会拼到一起

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

#include<stdio.h>

#define A(X,Y) X##Y 

int main()
{
    
    
	int tmp123 = 123;
	printf("%d\n", A(tmp, 123));
	return 0;
}

输出:

123

上面的 printf("%d\n", A(tmp, 123)); 相当于 printf("%d\n", tmp123);

例3:

#include<stdio.h> 
#include<limits.h> 
 
#define STR(s)     #s 
#define CONS(a,b)  (int)(a##e##b) 
 
int main() 
{
    
     
    printf(STR(vck));           // 输出字符串"vck" 
    printf("%d\n", CONS(2,3));  // 2e3 输出:2000   2e3是科学计数法  2 * 10 ^3
    return 0; 
}

二、当有##、#的宏定义时,宏中的参数若还是宏定义,此时该宏不会被展开

#define X  2
#define MAX_NUM 7000

#define INT(x)  #x

#define CON(x)  int(x##x)

printf("%s", INT(MAX_NUM));
printf("%d", CON(X));
 
//宏定义展开后:
//printf("%s", "MAX_NUM");
//printf("%d", int(XX));
//很明显,未达到目的

解决方法:加多一层中间转换宏
加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏 (_INT) (_CON) 就能得到正确的宏参数.

#define X  2
#define MAX_NUM 7000

#define _STR(x) #x        //转换宏
#define STR(x)  _STR(x)

#define _CON(x) int(x##x)
#define CON(x)  _CON(x)    //转换宏

printf("%s", INT(MAX_NUM));
printf("%d", CON(X));
 
//宏定义展开
//printf("%s", "7000");
//printf("%d", 22);

CON(X) =》_CON(X) =》int(22)
STR(MAX_NUM) =》_STR(MAX_NUM) =》“7000”

三、应用举例

1、合并匿名变量名

#define  ___ANONYMOUS1(type, var, line)  type  var##line 
#define  __ANONYMOUS0(type, line)  ___ANONYMOUS1(type, _anonymous, line) 
#define  ANONYMOUS(type)  __ANONYMOUS0(type, __LINE__) 

例:ANONYMOUS(static int); 即: static int _anonymous70; 70表示该行行号;
第一层:ANONYMOUS(static int); =》 __ ANONYMOUS0(static int, __LINE __ );
第二层: =》 ___ANONYMOUS1(static int, _anonymous, 70);
第三层: =》 static int _anonymous70;
即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;

2、填充结构

#define  FILL(a)   {a, #a} 
 
enum IDD{
    
    OPEN, CLOSE}; 
typedef struct MSG{
    
     
  IDD id; 
  const char * msg; 
}MSG; 

MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};
相当于:

MSG _msg[] = {
    
    {
    
    OPEN, "OPEN"}, 
              {
    
    CLOSE, "CLOSE"}}; 

3、记录文件名

#define  _GET_FILE_NAME(f)   #f 
#define  GET_FILE_NAME(f)    _GET_FILE_NAME(f) 
static char  FILE_NAME[] = GET_FILE_NAME(__FILE__); 

4、得到一个数值类型所对应的字符串缓冲大小

#define  _TYPE_BUF_SIZE(type)  sizeof #type 
#define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type) 
char  buf[TYPE_BUF_SIZE(INT_MAX)]; 

=》 char buf[_TYPE_BUF_SIZE(2147483647)];
=》 char buf[sizeof(“2147483647”)];

这里相当于:
char buf[11];

猜你喜欢

转载自blog.csdn.net/weixin_44788542/article/details/113601856
今日推荐