[翻译] Effective C++, 3rd Edition, Item 2: 用 consts, enums 和 inlines 取代 #defines

GitLab中国区注册终极解决方案:绕过+86手机验证的实战技巧(2023最新) 本文详细解析了GitLab中国区注册时绕过+86手机验证的三种实战技巧,包括开发者工具调试方案、使用国际号码的变通方案以及本地化部署替代方案。通过技术分析和实践验证,帮助开发者顺利注册GitLab账号,提升团队协作效率。 阅读详情

Item 2: 用 consts, enums 和 inlines 取代 #defines

作者:Scott Meyers

译者:fatalerror99 (iTePub's Nirvana)

发布:http://blog.youkuaiyun.com/fatalerror99/

这个 Item 改名为“用 compiler(编译器)取代 preprocessor(预处理器)”也许更好一些,因为 #define 根本就没有被看作是语言本身的一部分。这是它很多问题中的一个。当你像下面这样做:

#define ASPECT_RATIO 1.653

compiler(编译器)也许根本就没有看见这个符号名 ASPECT_RATIO,在 compiler(编译器)得到源代码之前,这个名字就已经被 preprocessor(预处理器)消除了。结果,名字 ASPECT_RATIO 可能就没有被加入 symbol table(符号表)。如果在编译的时候,发现一个 constant(常量)使用的错误,你可能会陷入混乱之中,因为错误信息中很可能用 1.653 取代了 ASPECT_RATIO。如果,ASPECT_RATIO 不是你写的,而是在头文件中定义的,你可能会对 1.653 的出处毫无头绪,你还会为了跟踪它而浪费时间。在 symbolic debugger(符号调试器)中也会遇到同样的问题,同样是因为这个名字可能并没有被加入 symbol table(符号表)。

解决方案是用 constant(常量)来取代 macro(宏):

const double AspectRatio = 1.653;   // uppercase names are usually for
                                    // macros, hence the name change

作为一个 language constant(语言层面上的常量),AspectRatio 被 compilers(编译器)明确识别并确实加入 symbol table(符号表)。另外,对于 floating point constant(浮点常量)(比如本例)来说,使用 constant(常量)比使用 #define 能产生更小的代码。这是因为 preprocessor(预处理器)盲目地用 1.653 置换 macro name(宏名字)ASPECT_RATIO,导致你的 object code(目标代码)中存在多个 1.653 的拷贝,如果使用 constant(常量)AspectRatio,就绝不会产生多于一个的拷贝。

用 constant(常量)代替 #defines 时,有两个特殊情况值得提出。首先是关于 constant pointers(常量指针)的定义。因为 constant definitions(常量定义)通常被放在 header files(头文件)中(这样它们就可以被包含在多个 source files(源文件)中),除了 pointer(指针)指向的目标是常量外,pointer(指针)本身被声明为 const 更加重要。例如,在头文件中定义一个 constant char*-based string(基于 char* 的字符串常量)时,你必须写两次 const:

const char * const authorName = "Scott Meyers";

对于 const(特别是与 pointers(指针)相结合时)的意义和使用的完整讨论,请参见 Item 3。然而在此值的一提的是,string objects(对象)通常比它的 char*-based(基于 char*)的祖先更可取,所以,更好的 authorName 的定义方式如下:

const std::string authorName("Scott Meyers");

第二个特殊情况涉及到 class-specific constants(类属(类内部专用的)常量)。为了将一个 constant(常量)的作用范围限制在一个 class(类)内,你必须将它作为一个类的 member(成员),而且为了确保它最多只有一个 constant(常量)拷贝,你还必须把它声明为一个 static member(静态成员)。

class GamePlayer {

private:

  static const int NumTurns = 5;      // constant declaration

  int scores[NumTurns];               // use of constant
  ...
};

你从上面只看到了 NumTurns 的 declaration(声明),而不是 definition(定义)。通常,C++ 要求你为你使用的任何东西都提供一个 definition(定义),但是一个 static(静态)的 integral type(整型族)(例如:integers(整型),chars,bools)的 class-specific constants(类属常量)是一个例外。只要你不去取得它们的 address(地址),你可以只声明并使用它,而不提供它的 definition(定义)。如果你要取得一个 class constant(类属常量)的 address(地址),或者你使用的 compiler(编译器)在你没有取得 address(地址)时也不正确地要求 definition(定义)的话,你可以提供如下这样一个独立的 definition(定义):

const int GamePlayer::NumTurns;     // definition of NumTurns; see
                                    // below for why no value is given

你应该把它放在一个 implementation file(实现文件)而非 header file(头文件)中。因为 class constants(类属常量)的 initial value(初始值)在声明时已经提供(例如:NumTurns 在定义时被初始化为 5),因此在定义处允许没有 initial value(初始值)。

注意,顺便提一下,没有办法使用 #define 来创建一个 class-specific constant(类属常量),因为 #defines 不考虑 scope(作用范围)。一旦一个 macro(宏)被定义,它将大范围影响你的代码(除非在后面某处存在 #undefed)。这就意味着,#defines 不仅不能用于 class-specific constants(类属常量),而且不能提供任何形式的 encapsulation(封装),也就是说,没有类似 "private"(私有)#define 的东西。当然,const data members(const 数据成员)是能够被封装的,NumTurns 就是如此。

比较老的 compilers(编译器)可能不接受上面的语法,因为它习惯于将一个 static class member(静态类成员)在声明时就获得 initial value(初始值)视为非法。而且,in-class initialization (类内初始化)仅仅对于 integral types(整型族)和 constants(常量)才被允许。如果上述语法不能使用,你可以将 initial value(初始值)放在定义处:

class CostEstimate {

private:

  static const double FudgeFactor;   // declaration of static class
  ...                                // constant; goes in header file
};

const double                         // definition of static class

  CostEstimate::FudgeFactor = 1.35;  // constant; goes in impl. file

这就是你所要做的全部。仅有的例外是当在类的编译期需要 value of a class constant(一个类属常量的值)的情况,例如前面在声明 array(数组)GamePlayer::scores 时(compilers(编译器)必须在编译期知道 array(数组)的 size(大小))。如果 compilers(编译器)(不正确地)禁止这种关于 static integral class constants(静态整型族类属常量)的 initial values(初始值)的使用方法的 in-class specification(规范),一个可接受的替代方案被亲切地(并非轻蔑地)昵称为 "the enum hack"。这项技术获得以下事实的支持:一个 enumerated type(枚举类型)的值可以用在一个需要 ints 的地方。所以 GamePlayer 可以被如下定义:

class GamePlayer {

private:

  enum { NumTurns = 5 };             // "the enum hack" - makes
                                     // NumTurns a symbolic name for 5

  int scores[NumTurns];              // fine
  ...
};

the enum hack 有几个值得被人所知的原因。首先,the enum hack 的行为在几个方面上更像一个 #define 而不是 const,而有时这正是你所需要的。例如:可以合法地取得一个 const 的 address(地址),但不能合法地取得一个 enum 的 address(地址),这正像同样不能合法地取得一个 #define 的 address(地址)。如果你不希望人们得到你的 integral constants(整型族常量)的 pointer(指针)或 reference(引用),enum(枚举)就是强制约束这一点的好方法。(关于更多的通过编码的方法强制执行设计约束的方法,参见 Item 18 。)同样,使用好的 compilers(编译器)不会为 integral types(整型族类型)的 const objects(const 对象)分配多余的内存(除非你创建了这个对象的指针或引用),即使拖泥带水的 compilers(编译器)乐意,你也决不会乐意为这样的 objects(对象)分配多余的内存。像 #defines 和 enums(枚举)就绝不会导致这种 unnecessary memory allocation(不必要的内存分配)。

需要知道 the enum hack 的第二个理由是纯粹实用主义的,大量的代码在使用它,所以当你看到它时,你要认识它。实际上,the enum hack 是 template metaprogramming(模板元编程)的一项基本技术(参见 Item 48)。

回到 preprocessor(预处理器)上来,#define 指令的另一个普遍的(不好的)用法是实现看来像函数,但不会引起一个函数调用的开销的 macros(宏)。以下是一个用较大的宏参数调用函数 f 的 macro(宏):

// call f with the maximum of a and b

#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))

这样的 macro(宏)有数不清的缺点,想起来就让人头疼。

无论何时,你写这样一个 macro(宏),都必须记住为 macro body(宏体)中所有的 arguments(参数)加上括号。否则,当其他人在表达式中调用了你的 macro(宏),你将陷入麻烦。但是,即使你确实做到了这一点,你还是会看到意想不到的事情发生:

int a = 5, b = 0;

CALL_WITH_MAX(++a, b);               // a is incremented twice

CALL_WITH_MAX(++a, b+10);            // a is incremented once

这里,调用 f 之前 a 递增的次数取决于它和什么进行比较!

幸运的是,你并不是必须要和这样不知所云的东西打交道。你可以通过一个 inline function(内联函数)的 template(模板)来获得 macro(宏)的效率,以及完全可预测的行为和常规函数的类型安全(参见 Item 30):

template<typename T>                               // because we don't

inline void callWithMax(const T& a, const T& b)    // know what T is, we

{                                                  // pass by reference-to-

  f(a > b ? a : b);                                // const - see Item 20

}

这个 template(模板)产生一组函数,每一个获得两个相同类型的对象并使用其中较大的一个调用 f。这样就不需要为函数体内部的参数加上括号,也不需要担心多余的参数解析次数,等等。此外,因为 callWithMax 是一个真正的函数,它遵循函数的作用范围和访问规则。例如,谈论一个类的私有的 inline function(内联函数)会获得正确的理解,但是用 macro(宏)就无法做到这一点。

为了得到 consts,enums 和 inlines 的可用性,你需要尽量减少 preprocessor(预处理器)(特别是 #define)的使用,但还不能完全消除。#include 依然是基本要素,而 #ifdef/#ifndef 也继续扮演着重要的角色。现在还不是让 preprocessor(预处理器)完全退休的时间,但你应该给它漫长而频繁的假期。

Things to Remember

  • 对于 simple constants(简单常量),用 const objects(const 对象)或 enums(枚举)取代 #defines。
  • 对于 function-like macros(类似函数的宏),用 inline functions(内联函数)取代 #defines。
R_柱状图(加误差线,显著性差异) 先放最终效果图 结果图 # bar_plot 2021/01/19 # 导入所需的包 library(ggplot2) library(ggthemr) library(ggsignif) library(tidyverse) library(dplyr) library(ggpubr) library(devEMF) # 导入并处理数据,需要两张表,一个是原始汇总表格,另外一些是每一... 阅读详情

相关推荐

Windows安全中心空白问题修复:服务重置与系统组件修复实战指南

Windows系统服务是操作系统后台运行的核心组件,负责管理硬件资源、应用程序执行和系统功能。其稳定运行依赖于服务控制管理器、注册表配置和系统文件完整性。当关键服务(如Windows Update、安全中心服务)因更新失败、权限错误或组件损坏而无法正常启动时,依赖其功能的应用程序界面便会出现加载异常。在系统维护与故障排除领域,通过命令行工具重置服务状态、修复系统映像已成为工程师的必备技能。本文聚焦Windows安全中心界面空白这一典型故障,深入剖析其与Windows Update服务、组件存储损坏的关联,并

weixin_30859423的博客 429

Swagger 使用

在NuGet中添加Swashbuckle 引用; 主要Swashbuckle 中已经包含了Swagger UI 与Swagger.net 不要重复引用。 引用完之后会在App_Start下生成 SwaggerConfig文件,如果还有一个SwaggerNet需要将这个删除掉。 c.RootUrl(ResolveBasePath); 这个为了解决域名访问问题  c...

weixin_30363981的博客 568

Linux系统安装AutoDockTools、AutoGrid和AutoDock并实现分子对接(详细讲解)

linux系统为centos7.0 按照下面操作安装AutoDockTools(MGLTools) 1. 下载安装包,链接(https://ccsb.scripps.edu/mgltools/downloads/),我的linux系统是64位,下载红色标记源代码,拷贝入linux目标文件夹下。 2. shell终端进行安装: 1. 终端进入安装包所在文件夹,并获取root权限;赋予代码安装权限; cd /home/... #目标文件夹,根据目标程序文件位置进行更改 su #获

carlos_zhao的博客 1万+

Effective C++之 Item 2: 用 consts, enums 和 inlines 取代 #defines

这个 Item 改名为“用 compiler(编译器)取代 preprocessor(预处理器)”也许更好一些,因为 #define 根本就没有被看作是语言本身的一部分。这是它很多问题中的一个。当你像下面这样做: #define ASPECT_RATIO 1.653 compiler(编译器)也许根本就没有看见这个符号名 ASPECT_RATIO,在 compiler(编译器)得到源代码之前,...

janeqi1987的专栏 325

Python APP反爬实战:Frida+Charles抓包,破解签名校验

Charles抓包定位参数 → jadx-gui反编译找函数 → Frida Hook拿密钥/规则 → Python还原签名算法;Frida的核心价值:Hook住APP的加密函数,拿到“输入(密钥/参数)+输出(签名)”,无需懂复杂的逆向底层;严格对齐APP的参数排序、拼接规则、加密算法,差一点都会验证失败。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1538

AI OS与LLM as OS:人工智能操作系统的崛起

近年来,随着大语言模型(Large Language Model, LLM)技术的突飞猛进,人工智能领域掀起了新的革命浪潮。以ChatGPT、GPT-4等为代表的LLM模型展现出了惊人的自然语言理解和生成能力,使得人机交互前所未有地拟人化、情境化。在此背景下,业界开始探索将LLM作为操作系统(Operating System, OS)的可能性,由此催生出"AI OS"和"LLM as OS"的概念。本文将深入解读这两个前沿概念,分析其内涵、技术原理、应用前景及面临的挑战。

AI天才研究院 996

Item 02: Prefer consts, enums, and inlines to #defines

Item 02: Prefer consts, enums, and inlines to #defines 尽量以 const,enum,inline 替换 #define 假如有这样的语句: #define ASPECT_RATIO 1.653 宏定义中的 ASPECT_RATIO 可能从未被编译器看见;也可能编译器处理之前就被预处理器给移走了。那么它很...

weixin_30616969的博客 152

【微电网优化】基于粒子群求解CHP机组、气网、电网、储热罐和电锅炉微电网优化模型附matlab代码

1 简介 我国风力发电近年发展迅速,装机容量已成为全球首位.随着风力发电在电力系统中的渗透率不断提高,我国多个地区(尤其是"三北"地区)已经面临着十分严峻的风电消纳问题,产生不容忽视的弃风问题.针对目前我国风电消纳存在的困难,本文提出粒子群优化CHP机组、气网、电网、储热罐和电锅炉微电网控制策略. 2 部分代码 Ppv=[0;0;0;0;0;0;9.86000000000000;19.0100000000000;33.1000000000000;45.0700000000000;64.7900000

qq_59747472的博客 672

深挖C++:类和对象(中)

(先进后出)

xys_678的博客 254

ABAP 7.40 新语法介绍系列之六:使用 FILTER 关键字对 ABAP 内表进行过滤

笔者之前写过的关于 ABAP 740 新语法的文章:本文介绍另一个新的关键字:FILTER.FILTER 是 ABAP 740 中引入的一个关键字,用于简化数据操作,它能够将内部表(Internal Table)中的数据按特定的条件进行过滤,并生成一个新的内部表。FILTER 的引入旨在使代码更加现代化和高效,尤其是在面对大量数据需要过滤的情况下。传统上,开发人员可能需要使用 LOOP AT 结合条件判断来实现,但使用 FILTER 关键字后,代码显得更加简洁且易于维护。

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

第六部分:VTK进阶(第182章 体素化与隐式建模)

本文系统介绍了基于点云构建有符号距离场(SDF)的核心原理与VTK实现方法。主要内容包括:1)SDF的基本概念与算法原理,通过体素网格隐式表达几何表面;2)关键参数配置指南,如体素分辨率、边界范围和影响半径的选择;3)点云法向估计、SDF计算与等值面提取的完整工作流程;4)常见问题解决方案与性能优化建议。文中提供了详细的C++代码示例,展示从随机点云生成SDF并重建曲面的完整过程,特别强调了法向估计、参数调优和后处理等关键环节。该方法适用于点云表面重建、几何处理等应用场景。

仰望星空的博客 530

ThunderKittens 深度解析:一个不基于 MLIR 的 C++ 模板 GPU DSL

Triton 是"让更多人能写 GPU kernel",ThunderKittens 是"让会写的人写得更爽"。前者用 MLIR 换易用性,后者用 C++ 模板换可控性。它们不是替代关系,而是覆盖了 GPU 编程光谱的两端。ThunderKittens 的出现,本质上是对"GPU DSL 必须基于 MLIR"这一默认假设的挑战。编译期类型系统本身就可以是一个强大的 DSL 基础设施,不需要中间 IR,不需要黑盒 pass,也能实现 tile 级抽象和零运行时开销。

Maxwell_Newton的博客 349

Windows部署小龙虾 OpenClaw 报错不断?参考这篇文章,轻松配置 OpenClaw 所需环境

想在Windows上部署OpenClaw却频频报错?🔧 本文详细梳理了OpenClaw部署必需环境的安装步骤和官方下载地址 📦,提供完整的验证清单和常见问题排查方法,帮你一次性搞定所有环境配置,顺利部署OpenClaw ✅

XiaoqiangClub的博客 364

C++移动构造函数详解

移动构造函数是C++11引入的一种特殊构造函数,用于从临时对象(右值)"窃取"资源来初始化新对象,而不是进行昂贵的深拷贝。char* data;public:// 移动构造函数:参数是右值引用 &&// 关键:把源对象的资源置空。

拒绝AI文,努力在AI时代写出感动人心的好文章 394

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

跟我学c++中级篇—类型定义的方式

本文系统阐述了编程中类型定义的重要性及c++中的实现方式。重点对比了宏定义、typedef与modern using三种机制,指出using在可读性、灵活性和模板支持上的优势,推荐优先使用。同时提醒开发者注意别名滥用、类型歧义、错误信息冗长等问题,强调统一规范与合理设计。最终结论:在现代c++开发中,应以using为主,兼顾简洁性与可维护性,避免陷入命名混乱与编译困境。

fpcc的专栏 88

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【C++——类和对象(上)】筑基篇:以封装奠定面向对象之基

本文系统梳理C++类与对象的核心知识点,涵盖类的定义、访问限定符(public/private)、类作用域、对象实例化及内存布局。重点解析封装思想、this指针机制、空类大小为1字节的原因,以及类与对象在内存中的存储差异。通过对比C语言结构体与C++类,揭示面向对象设计的优势:数据保护、接口统一、命名隔离与代码可维护性提升。内容由浅入深,适合作为学习笔记与复习参考。

2602_95684935的博客 486

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

C++ 函数模版

模板参数:● template ,T 就是类型占位符,名字可以自定义,习惯用T● 占位符可以在函数返回值、形参、函数内部当作类型使用使用要点模板代码一般写在头文件:编译器需要看到完整模板源码,才能在每个编译单元完成实例化全局函数、类内成员函数都可以写成模板实例化发生在编译阶段,不是运行时隐式实例化:调用时编译器自动推导实参类型,生成对应版本函数。

2501_94041724的博客 307

C++ 运行时多态与虚函数机制全面剖析【面试重点】

构成C++ 运行时多态必须是基类的指针或者引用调用虚函数。被调用的函数必须是虚函数,并且派生类必须对该虚函数完成重写/覆盖(Override)。只有基类的指针或引用才能既指向基类对象,又指向派生类对象(切片机制);而只有完成了虚函数重写,派生类与基类才具备不同的函数行为,达到“指向谁就调用谁”的效果。在类成员函数的前面加上virtual关键字修饰,该成员函数就成为了虚函数。public:// 成员函数前加 virtual 修饰,声明为虚函数。

Fuyo_0209的博客 450

#SQLite 数据库笔记一:(概念 / 终端指令 / SQL 语句 / C 编程 / 回调函数)

数据库 = 数据的仓库,假设数据是海量。能力说明存储数据持久化保存,程序退出数据还在统计数据、分组、排序数据管理增、删、改、查(CRUD)嵌入式设备上也会用数据库(单片机网关、路由器、工业 HMI 都常见),因为 sqlite 体积小、无需服务进程、单文件即可。数据库 = 库 > 表 > 记录(行) > 字段(列)sqlite3 = 开源、C 写的、单文件、免安装、最多 2T 的嵌入式关系型数据库。

lwq20051110的博客 251

1-10 PostgreSQL中多表连接全解:inner/left/right/full/cross join

本文基于 PostgreSQL 15+ 完整拆解 5 种主流连接:内连接、左连接、右连接、全连接、笛卡尔连接。结合可落地的测试数据,演示每种连接的执行逻辑、返回结果,重点剖析 NULL 值对 JOIN 匹配的核心影响,彻底解决多表连接数据丢失、匹配异常、结果错乱的问题。

zhangjw34的专栏 104

【C++ 基础入门】C++继承(下):问题、底层原理与组合

C++继承(菱形继承的问题、虚继承原理、继承与组合、构造顺序)

2601_96587588的博客 802

蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级 备考:莫队算法离线区间查询详解

备赛进行时:第十八届蓝桥杯软件赛报名已于 2026-10-08 10:00 开启、12-18 14:00 截止,省赛定在 2027-04-10(C/C++·Python 程序设计 9:00–13:00);中国电子学会 2026 年 12 月软件编程(C/C++ 一级至十级、Python 一级至六级)考级报名 9/23–12/2 16:00、统考 12-12;全国青少年信息素养大赛 2026—2027 赛季算法应用主题赛也已进入复盘练兵窗口。

IT_Scratch的博客 170

c++ explicit关键字详解

explicit。

拒绝AI文,努力在AI时代写出感动人心的好文章 151

825 mW 顶上 212 °C:ASM491S 的 105 °C/W、250 mA 短路电流与热关断

25 °C 环境里结温 34.1 °C,125 °C 环境里结温 134.1 °C——后者已经离 150 °C 只有 16 °C 了,但还在范围内。换个角度看同一件事:从 25 °C 和从 125 °C 起算,温升都是 86.6 °C,但一个到 111.6 °C(还在范围内),一个到 211.6 °C(远远超限)。这个算例里 20 °C/W 是我假设的,实际值取决于机壳材料、密封程度、有没有风扇,跨度可以从 5 °C/W 到 50 °C/W 以上。外面 50 °C 的机箱,盒内就是 63.9 °C。

ANSILIC的博客 393

《C++ 项目:手写大模型接入 SDK》Gemini接口设计(上):初始化、全量响应实现和测试

本文系统完成了Gemini模型通过OpenAI兼容API的接入开发,基于Apifox验证接口规范,设计并实现GeminiProvider类,涵盖初始化、状态检测、全量响应等核心功能。重点处理了代理配置强制校验、Bearer鉴权、JSON序列化与响应解析等工程细节,并通过GTest与CMake完成单元测试,验证链路可用性。项目遵循策略模式,保持与DeepSeek、ChatGPT等模型的统一抽象接口,显著提升SDK可扩展性。

2501_91275995的博客 398
上一篇: [翻译] Effective C++, 3rd Edition, Item 1: 将 C++ 视为语言的联合体
下一篇: [翻译] Effective C++, 3rd Edition, Item 3: 只要可能就用 const
fatalerror99
博客等级 码龄24年 166粉丝 20原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值