c++基础---C++宏定义详解

C++宏定义详解:从基础语法到高级应用 宏定义是C++预处理器提供的文本替换机制,在编译前完成代码转换。作为编译预处理的核心技术,宏通过#define指令实现常量定义、条件编译和代码生成等功能。其核心价值在于提供编译期代码灵活性,特别适用于平台适配、调试控制和代码复用场景。虽然现代C++推荐使用constexpr、模板等替代方案,但理解宏的字符串化(#)和标记连接(##)等高级特性,仍是处理遗留代码和特定优化场景的必备技能。在跨平台开发和模板元编程中,宏与预定义符号(如__LINE__、__cplusplus)的配合使用,能显著提升工程效率。 阅读详情

转自:http://blog.chinaunix.net/uid-21372424-id-119797.html

一、#define的基本用法

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利。

1 #define命令剖析

1.1   #define的概念

    #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。
该命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义。

(1)简单的宏定义:
  1. #define<宏名>  <字符串>
  2. 例: #define PI 3.1415926
(2) 带参数的宏定义
 
  1. #define<宏名>(<参数表>)<宏体>
  2. 例: #define A(x) x
    一个标识符被宏定义后,该标识符便是一个宏名。这时,在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换,替换后才进行编译, 宏替换是简单的替换。

1.2 宏替换发生的时机

    为了能够真正理解#define的作用,让我们来了解一下对C语言源程序的处理过程。当我们在一个集成的开发环境如Turbo C中将编写好的源程序进行编译时,实际经过了预处理、编译、汇编和连接几个过程。其中预处理器产生编译器的输出,它实现以下的功能:
(1) 文件包含
    可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。
(2)条件编译
    预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。
(3)宏展开
    预处理器将源程序文件中出现的对宏的引用展开成相应的宏 定义,即本文所说的#define的功能,由预处理器来完成。
    经过预处理器处理的源程序与之前的源程序有所有不同, 在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。

2 #define使用中的常见问题解析

2.1 简单宏定义使用中出现的问题

    在简单宏定义的使用中,当替换文本所表示的字符串为一个表达式时,容易引起误解和误用。如下例:
   
  1. 例1 #define N 2+2
  2. void main()
  3. {
  4.    int a=N*N;
  5.    printf(“%d”,a);
  6. }
    (1) 出现问题:
 
    在此程序中存在着宏定义命令,宏N代表的字符串是2+2,在程序中有对宏N的使用,一般同学在读该程序时,容易产生的问题是先求解N为2+2=4,然后在程序中计算a时使用乘法,即N*N=4*4=16, 其实该题的结果为8,为什么结果有这么大的偏差?

    (2) 问题解析:
 
    如1节所述, 宏展开是在预处理阶段完成的,这个阶段把替换文本只是看作一个字符串,并不会有任何的计算发生,在展开时是在宏N出现的地方 只是简单地使用串2+2来代替N,并不会增添任何的符号,所以对该程序展开后的结果是a=2+2*2+2,计算后=8,这就是宏替换的实质,如何写程序才能完成结果为16的运算呢?

    (3)解决办法:
 
  1. /*将宏定义写成如下形式*/
  2. #define N(2+2)
  3. /*这样就可替换成(2+2)*(2+2)=16*/

2.2 带参数的宏定义出现的问题

    在带参数的宏定义的使用中,极易引起误解。例如我们需要做个宏替换能求任何数的平方,这就需要使用参数,以便在程序中用实际参数来替换宏定义中的参数。一般学生容易写成如下形式:
  1. #define area(x) x*x
  2. /*这在使用中是很容易出现问题的,看如下的程序*/

  3. void main()
  4. {
  5.     int y = area(2+2);
  6.     printf(“%d”,y);
  7. }
    按理说给的参数是2+2,所得的结果应该为4*4=16,但是错了,因为该程序的实际结果为8,仍然是没能遵循纯粹的简单替换的规则,又是先计算再替换 了, 在这道程序里,2+2即为area宏中的参数,应该由它来替换宏定义中的x,即替换成2+2*2+2=8了。那如果遵循(1)中的解决办法,把2+2 括起来,即把宏体中的x括起来,是否可以呢?#define area(x) (x)*(x),对于area(2+2),替换为(2+2)*(2+2)=16,可以解决, 但是对于area(2+2)/area(2+2)又会怎么样呢,有的学生一看到这道题马上给出结果,因为分子分母一样,又错了,还是忘了遵循先替换再计算的规则了,这道题替换后会变为 (2+2)*(2+2)/(2+2)*(2+2)即4*4/4*4按照乘除运算规则,结果为16/4*4=4*4=16,那应该怎么呢?解决方法是在整个宏体上再加一个括号,即 #define   area(x) ((x)*(x)), 不要觉得这没必要,没有它,是不行的。
    要想能够真正使用好宏定义,那么在读别人的程序时, 一定要记住先将程序中对宏的使用全部替换成它所代表的字符串,不要自作主张地添加任何其他符号,完全展开后再进行相应的计算,就不会写错运行结果。
    如果是自己编程使用宏替换,则在使用简单宏定义时,当字符串中不只一个符号时,加上括号表现出优先级,如果是带参数的宏定义,则要给宏体中的每个参数加上括号,并在整个宏体上再加一个括号。
【总之,宏替换时,程序中只要出现宏名的地方就先用原样宏体替换,然后把宏体中的参数换成宏名调用地方传的参数即可。宏定义时,如果是无参数的单体表达式则无需任何括号;如果是无参数的多体表达式则需要给整个宏体加一个括号,总共就一个括号;如果是带参数的表达式,则需要给各个参数加一个括号,整个宏体也要加一个括号,总共多于两个括号。】
看到这里,不禁要问,用宏定义这么麻烦,这么容易出错,可不可以摒弃它, 那让我们来看一下在C语言中用宏定义的好处吧。
如:
  1. #include <iostream.h>
  2. #define product(x)    x*x
  3. int main()
  4. {
  5.     int i=3;
  6.     int j,k;
  7.     j = product(i++);
  8.     cout<<"j="<<j<<endl;
  9.     cout<<"i="<<i<<endl;
  10.     k = product(++i);
  11.     cout<<"k="<<k<<endl;
  12.     cout<<"i="<<i<<endl;
  13.     return 0;
  14. }
依次输出结果:
j=9;i=5;k=49;i=7


3 宏定义的优点

(1)   方便程序的修改

    使用简单宏定义可用宏代替一个在程序中经常使用的常量,这样在将该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可,而且当常量比较长时, 我们可以用较短的有意义的标识符来写程序,这样更方便一些。我们所说的常量改变不是在程序运行期间改变,而是在编程期间的修改,举一个大家比较熟悉的例子,圆周率π是在数学上常用的一个值,有时我们会用3.14来表示,有时也会用3.1415926等,这要看计算所需要的精度,如果我们编制的一个程序中 要多次使用它,那么需要确定一个数值,在本次运行中不改变,但也许后来发现程序所表现的精度有变化,需要改变它的值, 这就需要修改程序中所有的相关数值,这会给我们带来一定的不便,但如果使用宏定义,使用一个标识符来代替,则在修改时只修改宏定义即可,还可以减少输入 3.1415926这样长的数值多次的情况,我们可以如此定义 #define   pi   3.1415926,既减少了输入又便于修改,何乐而不为呢?

(2) 提高程序的运行效率

    使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子 函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽 略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问 题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况来决定是否使用宏定义。

4 结语

    本文对C语言中宏定义#define在使用时容易出现的问题进行了解析,并从C源程序处理过程的角度对#define的处理进行了分析,也对它的优点进行 了阐述。只要能够理解宏展开的规则,掌握使用宏定义时,是在预处理阶段对源程序进行替换,只是用对应的字符串替换程序中出现的宏名,这样就可在正确使用的 基础上充分享受使用宏定义带来的方便和效率了

二、define中的三个特殊符号:#,##,#@

  1. #define Conn(x,y) x##y
  2. #define ToChar(x)#@x
  3. #define ToString(x)#x
(1)x##y表示什么?表示x连接y,举例说:
  1. int n = Conn(123,456);/* 结果就是n=123456;*/
  2. char* str= Conn("asdf","adf");/*结果就是 str = "asdfadf";*/
(2)再来看 #@x ,其实就是给x加上单引号,结果返回是一个const char。举例说:
char a = ToChar(1);结果就是a='1';
做个越界试验char a = ToChar(123);结果就错了;
但是如果你的参数超过四个字符,编译器就给给你报错了!
error C2015: too many characters in constant   :P
(3)最后看看#x,估计你也明白了,他是给x加双引号
char* str = ToString(123132);就成了str="123132";
三、常用的一些宏定义

1 防止一个头文件被重复包含
  1. #ifndef BODYDEF_H
  2. #define BODYDEF_H
  3.  //头文件内容

  4. #endif
 
2 得到指定地址上的一个字节或字

  1. #define MEM_B( x)(*((byte*)(x)))
  2. #define MEM_W( x)(*((word*)(x)))
用法如下:
  1. #include<iostream>
  2. #include<windows.h>

  3. #define MEM_B(x)(*((byte*)(x)))
  4. #define MEM_W(x)(*((WORD*)(x)))

  5. int main()
  6. {
  7.     int bTest = 0x123456;

  8.     byte m = MEM_B((&bTest));/*m=0x56*/
  9.     int n = MEM_W((&bTest));/*n=0x3456*/

  10.     return 0;
  11. }

3 得到一个field在结构体(struct)中的偏移量

 
  1. #defineOFFSETOF( type, field) ( (size_t) &(( type*) 0)-> field)
    请参考文章:详解写宏定义:得到一个field在结构体(struct type)中的偏移量。

4 得到一个结构体中field所占用的字节数
  1. #define FSIZ( type, field)sizeof(((type*) 0)->field)

5 得到一个变量的地址(word宽度)
  1. #define B_PTR( var)((byte *)(void*)&(var))
  2. #define W_PTR( var)((word *)(void*)&(var))
6 将一个字母转换为大写

  1. #define UPCASE( c)(((c)>=''a''&&(c)<=''z'')?((c)- 0x20): (c))
7 判断字符是不是10进值的数字

  1. #define DECCHK( c)((c)>=''0''&&(c)<=''9'')
8 判断字符是不是16进值的数字
  1. #define HEXCHK( c)(((c)>=''0''&&(c)<=''9'')||((c)>=''A''&&(c)<=''F'')||((c)>=''a''&&(c)<=''f''))
9 防止溢出的一个方法

  1. #define INC_SAT( val)(val= ((val)+1>(val))?(val)+1:(val))
10 返回数组元素的个数
  1. #define ARR_SIZE( a)(sizeof((a))/sizeof((a[0])))
11 使用一些宏跟踪调试

ANSI标准说明了五个预定义的宏名。它们是:
  1. _LINE_ /*(两个下划线),对应%d*/
  2. _FILE_ /*对应%s*/
  3. _DATE_ /*对应%s*/
  4. _TIME_ /*对应%s*/
鼎捷T100二次开发实战:如何给开窗功能加上权限锁(附完整代码) 本文详细解析了鼎捷T100二次开发中开窗功能权限锁的实现方法,提供了两种技术方案:开窗程序重构法和动态WHERE条件注入法,并附上完整代码示例。通过真实案例,帮助开发者解决数据权限细粒度控制的难题,提升ERP系统的安全性和实用性。 阅读详情

相关推荐

淘特App x-sign参数逆向实战:从抓包到算法定位

本文详细解析了淘特App的x-sign参数逆向过程,从抓包分析到算法定位,涵盖了使用jadx-gui进行静态分析、Frida动态Hook验证以及Native层算法还原等关键技术。文章重点介绍了x-sign参数的生成机制及其在阿里系应用中的安全防护策略,为逆向工程师提供了实用的调试技巧和对抗策略。

5b6n7m8的博客 226

c/c++中的宏

c/c++中宏的学习

StudyWinter的博客 1万+

Chapter 19 Digital Phase-Locked Loops

数字锁相环 Digital Phase-Locked Loops, 就是根据原来时钟信号, 产生新的时钟信号, which is locked or synchronized. (align 参考时钟边沿 or 在中间)

2304_76736886的博客 972

c++基础——宏定义

宏定义 宏定义的格式如下#define 标识符 替换内容主要有三种类型 定义常量符号:#define PI 3.1415926 定义简单表达式:#define add(a,b) a+b 定义代码段 #define func(a) { \ printf("hello %s", a); \ } 由于宏在预处理阶段仅仅是做简单的替换,因此有时候会出现一些问题,例如如下代码define.cc #include <cstdio> #define add(a,b) a+b int main

超级码力 1750

GPU架构(1.1)--介绍 GPU的 VPU(Vision Processing Unit)架构

基于自研的 VPU(Vision Processing Unit)架构,专为高性能图形处理和深度学习设计。VPU 架构通过优化计算单元、内存层次结构、同步机制和指令流水线,提供了卓越的性能和能效。VPU 架构通过优化计算单元、内存层次结构、同步机制和指令流水线,提供了卓越的性能和能效。这种架构不仅适用于高性能图形处理,还广泛应用于深度学习、科学计算和边缘计算等领域。通过了解 VPU 架构的详细设计和工作原理,读者可以更好地利用这些先进的 GPU 技术,开发出高效、可靠的计算系统。

MHD0815的博客 1298

【腾讯小龙虾WorkBuddy专栏04】一文搞懂WorkBuddy的「专家」和「专家团」

WorkBuddy专家与专家团:专业级AI协作解决方案 WorkBuddy的专家(Expert)与专家团(Expert Team)功能颠覆了通用AI的局限性,提供角色化、可交付的专业服务。 核心优势 专家:深度垂直领域的AI顾问,具备人设、方法论、工具链,如全栈开发专家能直接交付完整项目,而非代码片段。 专家团:多智能体协作,自动拆解复杂任务(如竞品分析、全栈开发)并分发给对应角色,并行执行后整合输出,效率提升显著。 使用场景 单专家:解决专业问题(如SQL优化、UI设计)。

AI人人懂 2012

谈谈#define st(x) do { x } while (__LINE__ == -1) 的理解

#define HAL_ENTER_CRITICAL_SECTION(x) st( x = EA; HAL_DISABLE_INTERRUPTS(); ) #define HAL_EXIT_CRITICAL_SECTION(x) st( EA = x; ) 其中st(x)应作何解释? #define st(x) do { x } while (__LINE__ == -1)

oyyj42的专栏 4477

Modis数据处理工具:MRT百度网盘下载和手把手图文安装教程

如下图所示为MODIS Reprojection Tool(MRT)的软界面,看似简单,却是Modis遥感影像必不可少的处理工具,如投影变换等。本文以图文并茂的形式,详细讲解MRT软件在Windows10平台上的安装过程,并附MRT软件百度网盘下载地址。 Modis Tool主界面: 一、安装过程 1、安装Java运行环境 双击Java.exe,安装运行环境。默认的安装路径为C:\Program Files (x86)\Java\jre6\bin,后面需要用到这个路径。 等待...

智慧空间实验室 2621

C++的宏定义

C++的宏定义 总览 1.不带参数的宏定义与带参数的宏定义(宏函数) 2.宏替换时机与常用预定义宏 3.宏使用注意事项(简单替换,dowhile来规避分号吞噬) 4.宏函数的特定用法(#创建字符串与##粘合剂) 正文 ​ #define命令是C语言中的一个宏定义命令,该命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义。 不带参数的宏定义:#define 标识符 字符串 说明: (1)宏名一般用大写 (2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定

weixin_40212653的博客 2046

智能车图像处理5-入门级分析4 ---环岛的状态机与补线

PS :入门级文章适合新手,如果已经有基础可以去看进阶篇文章。

taiyuezyh的博客 8219

(功能安全六)硬件FMEDA计算

FMEDA(故障模式、影响与诊断分析)是功能安全验证的核心方法,通过量化分析硬件故障模式及其影响,计算SPFM、LFM、PMHF等关键指标。分析过程包含六大步骤:计算元器件失效率、识别故障模式、评估安全机制诊断覆盖率、分类计算各类失效率、量化指标计算及设计优化。输入需要系统架构图、硬件故障模式清单等资料,输出安全指标达标情况及改进建议,确保设计满足ASIL等级要求。该方法通过系统化的故障分类和量化评估,为硬件安全设计提供科学依据。

Dayongger的博客 1447

C++基础梳理(五):头文件和源文件的区别

/ 包含其他头文件// 类定义private:int data;

2301_81171484的博客 712

在 ABAP 世界把 SAML 2.0 玩明白:跨域 SSO 的通信模式、配置路径与落地实践

摘要 SAML 2.0是ABAP平台实现标准化SSO的推荐方案,提供Front-Channel(浏览器传递SAML报文)和Back-Channel(使用工件绑定通过SOAP兑换断言)两种通信方式。前者包括HTTP Redirect和POST绑定,后者通过Artifact绑定提升安全性。配置重点包括:激活ICF服务、使用SAML2事务码建立信任、设置用户标识映射、选择绑定方式(POST易调试、Artifact更安全)及配置安全策略(签名/加密)。典型流程包括SP-initiated和IdP-initiated

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 290

cpp笔记

流操作符<<与>>“<<”:流输入操作符“>>”:流提取操作符/=运算符一般是用于整数运算,等价于a = a/b;如果是std::filesystem::path类型,可以用该运算符作字符串拼接,如:c++关键字说明extern :c++ 结构体struct与类的区别。

weixin_37472852的博客 312

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

基础10:枚举+ 宏定义+类型重命名typedef

程序中的数字有时含义不明,被称为魔术数字。通常使用符号来表示。常用的方式有解决这种问题(1)const// 星期(2)#define// 星期作用域12。

Pierce110110的博客 756

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

虚幻引擎基础入门(C++) — 【宏定义 06】

本文简单介绍了虚幻引擎中的宏定义的使用

子枫 1248

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C++基础

其实wchar_t是这样的所以wchar_t实际上的空间是和shortint一样。一旦把引用初始化为某个变量,就可以通过原始变量名称或引用名称来访问变量的内容;(2)C++中的String类(和golang一样了)12、引用,引用变量是一个别名,某个已存在变量的另一个名字。14、C++数据结构(go的结构体)是一个变量,其值为另一个变量的地址。(1)标准输出流(cout)(3)标准错误流(cerr)(4)标准日志流(clog)(2)标准输入流(cin)(2)C++中使用指针。......

每一个不曾起舞的日子,都是对生命的辜负 319

C++中的宏定义详解

转载自:C++中的宏定义和C++宏定义详解 一、#define解析 #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利。 1 #define命令剖析 1.1 #define的概念 #define命令是C语言中的一个...

qq_32584715的博客 1万+

C++ 宏定义详解

关于宏定义的知识进行详细总结。

zxy_ZXY123的博客 4178

C++ 宏定义

———————— #define基本用法 ————————#define命令是C语言中的一个宏定义命令,它用来将一个标识符(宏名)定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。程序编译之前,编译的时候所有的宏名都会被定义的字符串替换,这便是宏替换。理解宏定义的关键在于 “替换”。该命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义。(1)简单的宏定义: #defi

shuzfan的专栏 4万+

C++宏定义详解

宏定义self: 作用:把一个标识符定义(宏名)为字符串(替换文本),便于程序修改,同时使函数模块化,提高运行效率 形式:简单宏定义,带参数宏定义 c语言源程序处理过程:预处理、编译、汇编和连接 其中预处理过程包括宏展开,所以宏定义先宏展开后编译; C++宏定义详解 一、#define的基本用法 #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定...

a1059682127的博客 1002

C++开发基础之宏定义

宏定义的工作原理涉及到宏的解析和展开过程,以及如何使用带参数的宏。通过对这些过程的理解,我们可以更清楚地掌握宏定义在代码中的作用。当我们讨论如何定义简单的宏和带参数的宏时,我们需要考虑如何使用#define关键字来创建这些宏。使用#define关键字可以定义简单的宏,通常用于定义常量或简单的替换文本。(a) : (b))其中,第一个宏定义了常量PI,第二个宏定义了一个比较大小的函数式宏。带参数的宏可以通过在宏定义中使用参数来实现更灵活的功能。这里,SQUARE宏接受一个参数并返回该参数的平方,而。

dotnet研习社 2096

C语言基础(五)自定义类型与宏定义

自定义类型与宏定义一、自定义类型二、宏定义 一、自定义类型 自定义类型 typedef用新的类型名代替原有的类型名 例如 //指定用u8为类型名,作用与unsigned char相同 typedef unsigned char u8; u8 x; //指定用Integer为类型名,作用与int相同。 typedef int Integer; //指定用Real为类型名,作用与float相同。 typedef float Real; #include <stdio.h> int main() {

qq_42585108的博客 1195

c++宏定义详解

C++宏定义详解 一、#define的基本用法 #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利。 1 #define命令剖析 1.1 #define的概念 #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标

weixin_52303681的博客 1296
上一篇: WPF透明窗体制作
下一篇: windows消息机制总结(包括mfc,.Net)
HNFXS985
博客等级 码龄14年 219粉丝 150原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值