C/C++ 的宏中:

  (1) # 的功能是将其后面的宏参数进行字符串化操作,简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。

  也就是说:

  #define __TO_STRING_IMPL(x) #x 

  中的#X, 则宏变量X所引用的是宏参数中的X,因为,#X会直接对参数X进行字符串化,因此该参数输出的是字符串“X”。

  使用: __TO_STRING_IMPL(15), 输出:“15”

  为了能够进一步增加宏的参数输入,因此需要在外部再包括一个宏转化,这样就可以把"转化宏"中的具体参数传入到参数化宏中,这样就可以变为相应“具体参数”的字符串。

  如下图所示:

  #define __TO_STRING(x) __TO_STRING_IMPL(x)

  (2) ##连接符号由两个井号组成,其功能是在带参数的宏定义中将两个子串联接起来,从而形成一个新的子串。但它不可以是第一个或者最后一个子串。

  作用:只是用所引用的宏变量替换后,将两个字符串串接起来,形成新的字符串。

  如下:

  #define A(x) T_##x

  使用:A(1),则输出:T_1

  

  (3)#@, 表示将参数作为字符形式替换

  如下:

  #define B(x) #@x

  使用: B(1),输出:’1‘

凡是宏定义里有用#或##的地方宏参数是不会再展开,例如_STRI(INT_MAX)中的INT_MAX就不会被展开为2147483647。  

如果想要使其中的宏参数展开,则需要多加一层中间转换宏: #define STRI(s) _STRI(s)  

加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的宏就能得到对应的宏参数。

  

#ifndef __TO_STRING
#define __TO_STRING_IMPL(x) #x
#define __TO_STRING(x) __TO_STRING_IMPL(x)
#endif

  例子如下:

#include "stdafx.h"
#include <iostream> #include<stdio.h> using namespace std; #define f(a,b) a##b
#define g(a) #a
#define h(a) g(a) #define A(x) T_##x
#define B(x) #@x
#define C(x) #x //如果EXP为真, 则输出宏参数“EXP”所指的字符串,
//注意:参数直接用真实参数替换。
#define WARN_IF(EXP) if(EXP) cerr << #EXP << endl;
//将红参数“n”,真实参数替换后
#define paster( n ) cout << "token" << #n << " = " << n << endl;
//两个宏参数,连接“宏参数”替换后形成字符串
#define _CONS(a, b) int(a##+##b)
#define _STRI(s) #s
#define STRI(s) _STRI(s) void test_sharp_symbol()
{
printf("%s\n", h(f(, ))); //输出:12 因为:h是转化的宏,其参数还是一个宏变量,则需要转化。
printf("%s\n", g(f(, ))); //输出:f(1,2) 因为:g直接把指代的参数以“字符串”输出
printf("%s\n", h(A())); // A(1)------〉T_1
printf("%d\n", B()); // B(1)------〉'1'
printf("%s\n", C()); // C(1)------〉"1" int div = ;
WARN_IF(div == ); //输出: div == 0
paster(); //输出: token9 = 9
cout << _CONS( + , ) << endl; //输出: 5 , 即: int(3+2), 输出5
cout << _STRI(INT_MAX) << endl; //输出: INT_MAX ,因为INT_MAX,本质上是一个宏,但是作为宏参数,则直接以字符串输出。
cout << STRI(INT_MAX) << endl; // prints : 2147483647 因为: INT_MAX ,再 STRI中已经替换为真实“数据”,从而可以以字符串输出
} int _tmain(int argc, _TCHAR* argv[])
{
test_sharp_symbol(); system("pause");
return ;
}

输出如下:

C/C++ 的宏中#和##的作用和展开的更多相关文章

  1. C/C++ 宏中的 #、#@、##的作用

    宏中的# 功能是将其后面的宏参数进行字符串化操作(Stringizing operator), 简单说就是在它引用的宏变量的左右各加上一个双引号. #define STRING(x) #x 下面二条语 ...

  2. C/C++语言中#的神奇作用:把宏参数字符串化/贴合宏参数

    宏中"#"和"##"的用法 一.一般用法   我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起. #define STR(s)      #s # ...

  3. C函数和宏中的可变参数

    一:调用惯例 函数的调用方和被调用方对函数如何调用应该有统一的理解,否则函数就无法正确调用.比如foo(int n, int m),调用方如果认为压栈顺序是m,n,而foo认为压栈顺序是n, m,那么 ...

  4. web.xml中load-on-startup的作用

    如下一段配置,熟悉DWR的再熟悉不过了:<servlet>   <servlet-name>dwr-invoker</servlet-name>   <ser ...

  5. C#中构造函数的作用

    C#中构造函数的作用 共同点: 都是实例化对象,初始化数据的 默认构造是说所有的类都从祖先object那继承了空参的构造方法,你不写与写空参构造都存在,而有参数的构造一般是自己写的,写就有不写就没有, ...

  6. MySQL数据库中delimiter的作用概述

    以下的文章主要是向大家描述的是MySQL数据库中delimiter的作用是什么?我们一般都认为这个命令和存储过程关系不大,到底是不是这样的呢?以下的文章将会给你相关的知识,望你会有所收获. 其实就是告 ...

  7. js中getBoundingClientRect的作用及兼容方案

    js中getBoundingClientRect的作用及兼容方案 1.getBoundingClientRect的作用 getBoundingClientRect用于获取某个html元素相对于视窗的位 ...

  8. Linq中关键字的作用及用法

    Linq中关键字的作用及用法 1.All:确定序列中的所有元素是否都满足条件.如果源序列中的每个元素都通过指定谓词中的测试,或者序列为空,则为 true:否则为 false. Demo: 此示例使用 ...

  9. JAVA中protected的作用

    JAVA中protected的作用   1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是 ...

随机推荐

  1. Linux下安装GitHub

    安装GitHub 1.下载安装git: yum -y install git git-core git-doc 2.运行完执行 ssh-keygen -t rsa -C "your@emai ...

  2. 代码: !AJAX

    http://www.cnblogs.com/cwp-bg/p/7668840.html ajax和jsonp使用总结 2017-10-17 var requestUrl="http://l ...

  3. Vue开源项目汇总(史上最全)(转)

    目录 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 UI组件 element ★13489 - 饿了么出品的Vue2的web UI工具套件 Vux ★8133 - 基于Vue和 ...

  4. Linux的Namespace与Cgroups介绍

    Namespace 的概念 Linux Namespace 是kernel 的一个功能,它可以隔离一系列系统的资源,比如PID(Process ID),User ID, Network等等.一般看到这 ...

  5. tcp的发送端一个小包就能打破对端的delay_ack么?

    3.10内核,反向合入4.9的bbr. 最近分析bbr的时候,收集了线上的一些报文,其中有一个疑问一直在我脑海里面,如下: 本身处于delay_ack状态的客户端,大概40ms回复一个delay_ac ...

  6. 简单定时器的Java实现

    这两个类使用起来非常方便,可以完成我们对定时器的绝大多数需求 Timer类是用来执行任务的类,它接受一个TimerTask做参数 Timer有两种执行任务的模式,最常用的是schedule,它可以以两 ...

  7. CORSFilter 跨域资源访问

    CORS 定义 Cross-Origin Resource Sharing(CORS)跨来源资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 ...

  8. 如何编写Window服务程序(C# )

    虚拟需求:编写一个Window服务,并注册到操作系统的服务里.让他隔30秒运行一下(写当前日期到一个文本里) 步骤: 创建一个Window 窗体应用程序项目(Greatwall.Mes.Windows ...

  9. KALI安装与环境配置

    2018-2019 201899224<网络攻防实践>第二周作业 虚拟化网络攻防实验环境包括以下部分: 靶机:包含系统和应用程序安全漏洞,并作为攻击目标的主机.(Windows XP和Li ...

  10. Linux 禁止普通用户su到root

    Linux账户权限管理上为了防止普通用户通过su切换到root用户,需要修改/etc/pam.d/su和/etc/login.defs两个配置文件. Step1:修改 /etc/pam.d/su文件 ...