浅析C++宏定义里#和##的使用

 更新时间:2023年05月18日 09:20:00   作者:爱跑步的码农  
工作中如果是c开发的话,经常会用到宏定义,而宏定义中的#和##也会时不时遇到,本文主要就来和大家分享一下这两个符号的作用,需要的可以参考一下

工作中如果是c开发的话,经常会用到宏定义,而宏定义中的#和##也会时不时遇到,今天分享这两个符号的作用。

1,# -- 转换成字符串

直接看例子:

#include <stdio.h>
#include <stdlib.h>
#define VAL2STR(VAL) (#VAL) 
#define fun_call_rt(func)		\
do								\
{								\
	int ret = func;				\
	if(ret){printf("%d = %s\n", ret, #func);} \
} while (0);
int func_for_test(int value);
int main()
{
	int val = 200;
	printf("%s\n", VAL2STR(200));
	fun_call_rt(func_for_test(10));
	return 0;
}
int func_for_test(int value)
{
	if(value == 100)
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

我们可以直接用gcc -E 预编译看看宏展开后是什么样的?如用命令 gcc -E test_#.c -o preprocess_test 编译后,我们看最后的代码:

其中的  VAL2STR(200) 被替换成了 ("200"),fun_call_rt(func) 中的 #func 被替换成了 "func_for_test(10)",即都被替换成了字符串,在c语言中应该称为字符数组类型。

在一些公司中类似 fun_call_rt(func) 宏几乎处处可见,在每个函数调用的地方都是这个宏括起来,一旦有错误发生,打印输出一目了然。

2, ## -- 连接两个语句为一个语句

这里所说的语句,可以是函数名,类型名,变量名,但都需要有实际意义,否则就会编译不过,看代码:

#include <stdio.h>
#include <stdlib.h>
#define NAME_JOIN(x,y) x##y
int func_for_test_1();
int main()
{
	printf("%p\n", NAME_JOIN(func_for_test, _1));
	return 0;
}
int func_for_test_1()
{
	return 10;
}

假如我改成 printf("%p\n", NAME_JOIN(func_for_test1, _1)); 在编译的时候会出现错误:

因为 NAME_JOIN(func_for_test1, _1) 只是简单的把两个短语连接为一个短语,而连接后的这个短语是否有效那就要做语法检测了,如上面执行的结果为:打印函数的地址

那如果改成这样:printf("ret = %d\n", NAME_JOIN(func_for_test, _1)()); 就是一个函数调用了,其结果就是:

而有一种情况这个 ## 可能不会是你想要的结果,那就是宏定义里又包含宏定义,如:

#include <stdio.h>
#include <stdlib.h>
#define NUMBER_1 _1
//#define NAME_JOIN(x,y) NAME_JOIN2(x,y)
#define NAME_JOIN(x,y) x##y
int func_for_test(int value);
int func_for_test_1();
int main()
{
        printf("ret = %d\n", NAME_JOIN(func_for_test, NUMBER_1)());
        return 0;
}
int func_for_test_1()
{
        return 10;
}

NAME_JOIN(func_for_test, NUMBER_1) 宏定义里又包含了宏 NUMBER_1,这样编译会出现什么问题呢?

可以看到  NUMBER_1 没有被展开,我们想要的是它被展开为 -1,即 func_for_test_1。处理办法就是再多加一个宏定义,如:

#include <stdio.h>
#include <stdlib.h>
#define NUMBER_1 _1
#define NAME_JOIN(x,y) NAME_JOIN2(x,y)
#define NAME_JOIN2(x,y) x##y
int func_for_test(int value);
int func_for_test_1();
int main()
{
        printf("ret = %d\n", NAME_JOIN(func_for_test, NUMBER_1)());
        return 0;
}
int func_for_test_1()
{
        return 10;
}

这样就能正确展开,编译成功。

以上就是浅析C++宏定义里#和##的使用的详细内容,更多关于C++宏定义的资料请关注脚本之家其它相关文章!

相关文章

  • 浅谈VC++中的内联

    浅谈VC++中的内联

    在 Visual C++ 中使用内联汇编 一、内联汇编的优缺点 因为在Visual C++中使用内联汇编不需要额外的编译器和联接器,且可以处理Visual C++ 中不能处理的一些事情,而且可以使用在 C/C++中的变量,所以非常方便。
    2015-07-07
  • C/C++举例讲解关键字的用法

    C/C++举例讲解关键字的用法

    相对于其他语言来说,C语言的关键字算是少的了。在C98中关键子总共只有32个,我们来分析一下部分关键字在C/C++中它独特的作用
    2022-05-05
  • C++ min/max_element 函数用法详解

    C++ min/max_element 函数用法详解

    这篇文章主要介绍了C++ min/max_element 函数用法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • C++中sln,vcxproj,vcxproj.filters,lib,dll,exe的含义说明

    C++中sln,vcxproj,vcxproj.filters,lib,dll,exe的含义说明

    这篇文章主要介绍了C++中sln,vcxproj,vcxproj.filters,lib,dll,exe的含义说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • win10+VS2017+Cuda10.0环境配置详解

    win10+VS2017+Cuda10.0环境配置详解

    这篇文章主要介绍了win10+VS2017+Cuda10.0环境配置详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • C语言实现通用数据结构之通用链表

    C语言实现通用数据结构之通用链表

    这篇文章主要为大家详细介绍了c语言实现通用数据结构之通用链表,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Objective-C不带加减号的方法实例

    Objective-C不带加减号的方法实例

    显而易见的事实是,Objective-C 中,+ 表示类方法,- 表示实例方法,这篇文章主要给大家介绍了关于Objective-C不带加减号的相关资料,需要的朋友可以参考下
    2021-06-06
  • 进程间通信之深入消息队列的详解

    进程间通信之深入消息队列的详解

    本篇文章是对消息队列的应用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言学习笔记之VS2022安装使用教程

    C语言学习笔记之VS2022安装使用教程

    这篇文章主要介绍了C语言学习笔记之VS2022安装使用教程,在VS2022中,在使用scanf函数编译出错,本文给大家提到了解决方法,需要的朋友可以参考下
    2022-05-05
  • 浅析C++浅拷贝与深拷贝的联系和区别

    浅析C++浅拷贝与深拷贝的联系和区别

    在c++中,深拷贝和浅拷贝也算是一个难点,特别是对于初学者来说,往往在不知道两者区别的情况下而错误的使用了浅拷贝,从而导致了野指针之类的问题,但是又因为缺少理解所以很难定位到问题所在
    2022-09-09

最新评论