C语言宏定义中的 “#” 和 “##”

#include <stdio.h>

// #(stringizing) 字符串化操作符。
// 作用:将宏定义中的传入参数名转换成用一对双引号括起来的参数名字符串。
// 其只能用于有参数传入的宏定义中,且必须置于宏定义参数名前面。 
// 对空格的处理:
//		1. 忽略传入参数名前后的空格;
//		2. 当传入参数名的中间存在空格时,编译器会自动连接各子字符串,
// 			且每个子字符串中只以一个空格连接,忽略多余一个的空格。 

#define EXP(x)		printf("The string is: \"%s\"\n", #x)

#define PRINT(x)	printf("\"%s\": ", #x);\
					printf("%d", x)						// 因为语句本身不能判断参数类型,所以显得不那么方便
														// 使用下面 C++ 的 cout 语法,可以很方便的输出; 

// 在C++中的妙用 					
// #define P(A) cout<<#A<<": "<<(A)<<endl;		

#define TEST	123	

int main(void)
{
	int abc = 5;			
	EXP(5);							// output: "5"
	EXP(abc);						// output: "abc"
	EXP(   abc   def    hig    ); 	// output: "abc def hig"
	EXP(TEST);						// output: "TEST"           // 即使参数也算一个宏定义,但是不会再展开了;即不能嵌套
	EXP(EXP(TEST));                 // output: "EXP(TEST)"
	
	PRINT(abc);                     // output: ["abc": 5]
	
	return 0;
}
#include <stdio.h>

// ##: 	记号粘贴操作符(token paste operator)
// 作用:先分隔,然后进行强制连接。
//			普通宏定义中,预处理器一般把空格解释成分段标志,对每一段和前面比较,
// 			相同的就被替换,但是这样的结果是:被替换后空格还是存在。
//			如果我们不希望出现这些空格,就可以通过 "##" 代替空格。
// 			如果 ## 前面出现空格,也会被编译器忽略。 
// 解释:这里的分隔类似于:"#define add(a,b) a+b" 中的 "+" 的作用,将两个参数分开。

// 以下实例可用于命名标准化 
#define A1(name, type)	type name_##type##_type		// 分隔成:"name_", "type", "_type" 三个token,所以只有 "type" 能匹配上 
#define A2(name, type)  type name##_##type##_type 	// 分隔成:"name", "_","type", "_type" 四个token,所以 "name", "type" 都能匹配上 
#define A3(name, type)  type name ##_##type  ##_type	// ## 前出现空格,被编译器忽略; 

int main(void)
{
	A1(a1, int);		// 相当于: int name_int_type; 
	A2(a2, float);		// 相当于:	float a2_float_type; 
	A3(a3, double); 
	
	name_int_type = 5;			// 编译正确,说明变量  name_int_type 已经存在; 
	a2_float_type = 3.14;		// 编译正确,说明变量  a2_float_type 已经存在; 
	a3_double_type = 3.1415926;	// 编译正确,说明变量  a3_double_type 已经存在; 
	
	return 0;
 } 
#include <stdio.h>

#define VAR1    123
#define stringizing(param)      #param
#define TO_STR(a)               stringizing(a)

#define F           abc
#define B           def
#define FB(arg)     #arg
#define FB1(arg)    FB(arg)

#define CONN(a, b)      a##b
#define pasiting(n)     printf("token" #n " = %d\n", token##n)

int main()
{
    printf("%s\n", TO_STR(VAR1));       // output: "123"
    printf("%s\n", stringizing(VAR1));  // output: "VAR1"
    printf("%s\n", FB(F B));            // output: "F B"
    printf("%s\n", FB1(F B));           // output: "abc def"
    
    int token9 = 8;
    int CONN(token, 8) = 7;
    printf("%s = %d\n", TO_STR(CONN(token, 8)), CONN(token, 8));    // output: "token8 = 7"
    printf("%s\n", TO_STR(CONN(x, y)));                             // output: "xy"
    // printf("%s\n", TO_STR(CONN(CONN(a, b), c)));                 // 编译出错,CONN不可嵌套使用
    pasiting(9);                                                    // output: "token9 = 8"
    
    return 0;
}

参考:

1.  宏定义中的#,##_业余飘向linux深谷-CSDN博客_宏定义中##

 2. Microsoft 官方解释

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值