C++函数声明和定义

使用QT的正则表达式库提取c++函数声明和函数定义 使用QT的正则表达式库提取c++函数声明和函数定义 提取函数声明的正则表达式比较简单,这里介绍一下自己偶然间想到的提取函数定义方法。有正则经验的可以直接看代码 一、提取函数声明 一个普通函数的声明通常由 返回类型 函数名(参数列表) 组成 但是在不同情况下,可以把正则表达式写成下面这些形式: 1.从函数定义中提取:如 void getName(){ } (\\b[A-Za-z0-9_]+\\s+\\b[A-Za-z0-9_]+\\s*\\(.*?\\))(?=\\s*\\{) 2.从函数声明中提取:如 阅读详情

声明的含义

     前面已经解释过声明是什么意思,在此由于成员函数的定义规则这种新的定义语法,必须重新考虑声明的意思。注意一点,前面将一个函数的定义放到main函数定义的前面就可以不用再声明那个函数了;同样如果定义了某个变量,就不用再声明那个变量了。这也就是说定义语句具有声明的功能,但上面成员函数的定义语句却不具有声明的功能,下面来了解声明的真正意思。
     声明是要求编译器产生映射元素的语句。所谓的映射元素,就是前面介绍过的变量及函数,都只有3栏(或3个字段):类型栏、名字栏和地址栏(成员变量类型的这一栏就放偏移值)。即编译器每当看到声明语句,就生成一个映射元素,并且将对应的地址栏空着,然后留下一些信息以告诉连接器——此.obj文件(编译器编译源文件后生成的文件,对于VC是.obj文件)需要一些符号,将这些符号找到后再修改并完善此.obj文件,最后连接。
     回想之前说过的符号的意思,它就是一字符串,用于编译器和连接器之间的通信。注意符号没有类型,因为连接器只是负责查找符号并完善(因为有些映射元素的地址栏还是空的)中间文件(对于VC就是.obj文件),不进行语法分析,也就没有什么类型。
     定义是要求编译器填充前面声明没有书写的地址栏。也就是说某变量对应的地址,只有在其定义时才知道。因此实际的在栈上分配内存等工作都是由变量的定义完成的,所以才有声明的变量并不分配内存。但应注意一个重点,定义是生成映射元素需要的地址,因此定义也就说明了它生成的是哪个映射元素的地址,而如果此时编译器的映射表(即之前说的编译器内部用于记录映射元素的变量表、函数表等)中没有那个映射元素,即还没有相应元素的声明出现过,那么编译器将报错。
     但前面只写一个变量或函数定义语句,它照样正常并没有报错啊?实际很简单,只需要将声明和定义看成是一种语句,只不过是向编译器提供的信息不同罢了。如:void ABC( float );和void ABC( float ){},编译器对它们相同看待。前者给出了函数的类型及类型名,因此编译器就只填写映射元素中的名字和类型两栏。由于其后只接了个“;”,没有给出此函数映射的代码,因此编译器无法填写地址栏。而后者,给出了函数名、所属类型以及映射的代码(空的复合语句),因此编译器得到了所有要填写的信息进而将三栏的信息都填上了,结果就表现出定义语句完成了声明的功能。
     对于变量,如long a;。同上,这里给出了类型和名字,因此编译器填写了类型和名字两栏。但变量对应的是栈上的某块内存的首地址,这个首地址无法从代码上表现出来(前面函数就通过在函数声明的后面写复合语句来表现相应函数对应的代码所在的地址),而必须由编译器内部通过计算获得,因此才硬性规定上面那样的书写算作变量的定义,而要变量的声明就需要在前面加extern。即上面那样将导致编译器进行内部计算进而得出相应的地址而填写了映射元素的所有信息。
     上面难免显得故弄玄虚,那都是因为自定义类型的出现。考虑成员变量的定义,如:
     struct ABC { long a, b; double c; };
     上面给出了类型——long ABC::、long ABC::和double ABC::;给出了名字——ABC::a、ABC::b和ABC::c;给出了地址(即偏移)——0、4和8,因为是结构型自定义类型,故由此语句就可以得出各成员变量的偏移。上面得出三个信息,即可以填写映射元素的所有信息,所以上面可以算作定义语句。对于成员函数,如下:
     struct ABC { void AB( float ); };
     上面给出了类型——void ( ABC:: )( float );给出了名字——ABC::AB。不过由于没有给出地址,因此无法填写映射元素的所有信息,故上面是成员函数ABC::AB的声明。按照前面说法,只要给出地址就可以了,而无需去管它是定义还是声明,因此也就可以这样:
     struct ABC { void AB( float ){} };
     上面给出类型和名字的同时,给出了地址,因此将可以完全填写映射元素的所有信息,是定义。上面的用法有其特殊性,后面说明。注意,如果这时再在后面写ABC::AB的定义语句,即如下,将错误:
     struct ABC { void AB( float ){} };
     void ABC::AB( float ) {}
     上面将报错,原因很简单,因为后者只是定义,它只提供了ABC::AB对应的地址这一个信息,但映射元素中的地址栏已经填写了,故编译器将说重复定义。再单独看成员函数的定义,它给出了类型void ( ABC:: )( float ),给出了名字ABC::AB,也给出了地址,但为什么说它只给出了地址这一信息?首先,名字ABC::AB是不符合标识符规则的,而类型修饰符ABC::必须通过类型定义符“{}”才能够加上去,这在前面已多次说明。因此上面给出的信息是:给出了一个地址,这个地址是类型为void ( ABC:: )( float ),名字为ABC::AB的映射元素的地址。结果编译器就查找这样的映射元素,如果有,则填写相应的地址栏,否则报错,即只写一个void ABC::AB( float ){}是错误的,在其前面必须先通过类型定义符“{}”声明相应的映射元素。这也就是前面说的定义仅仅填充地址栏,并不生成映射元素。


声明的作用

     定义的作用很明显了,有意义的映射(名字对地址)就是它来做,但声明有什么用?它只是生成类型对名字,为什么非得要类型对名字?它只是告诉编译器不要发出错误说变量或函数未定义?任何东西都有其存在的意义,先看下面这段代码。
     extern"C" long ABC( long a, long b );
     void main(){ long c = ABC( 10, 20 ); }
     假设上面代码在a.cpp中书写,编译生成文件a.obj,没有问题。但按照之前的说明,连接时将错误,因为找不到符号_ABC。因为名字_ABC对应的地址栏还空着。接着在VC中为a.cpp所在工程添加一个新的源文件b.cpp,如下书写代码。
     extern"C" float ABC( float a ){ return a; }
     编译并连接,现在没任何问题了,但相信你已经看出问题了——函数ABC的声明和定义的类型不匹配,却连接成功了?
     注意上面关于连接的说明,连接时没有类型,只管符号。上面用extern"C"使得a.obj要求_ABC的符号,而b.cpp提供_ABC的符号,剩余的就只是连接器将b.obj中_ABC对应的地址放到a.obj以完善a.obj,最后连接a.obj和b.obj。
     那么上面什么结果,由于需要考虑函数的实现细节,这在《C++从零开始(十五)》中再说明,而这里只要注意到一件事:编译器即使没有地址也依旧可以生成代码以实现函数操作符的功能——函数调用。之所以能这样就是因为声明时一定必须同时给出类型和名字,因为类型告诉编译器,当某个操作符涉及到某个映射元素时,如何生成代码来实现这个操作符的功能。也就是说,两个char类型的数字乘法和两个long类型的数字乘法编译生成的代码不同;对long ABC( long );的函数调用代码和void ABC( float )的不同。即,操作符作用的数字类型的不同将导致编译器生成的代码不同。
     那么上面为什么要将ABC的定义放到b.cpp中?因为各源文件之间的编译是独立的,如果放在a.cpp,编译器就会发现已经有这么个映射元素,但类型却不匹配,将报错。而放到b.cpp中,使得由连接器来完善a.obj,到时将没有类型的存在,只管符号。下面继续。
     struct ABC { long a, b; void AB( long tem1, long tem2 ); void ABCD(); };
     void main(){ ABC a; a.AB( 10, 20 ); }
     由上面的说法,这里虽然没有给出ABC::AB的定义,但仍能编译成功,没有任何问题。仍假设上面代码在a.cpp中,然后添加b.cpp,在其中书写下面的代码。
     struct ABC { float b, a; void AB( long tem1, long tem2 ); long ABCD( float ); };
     void ABC::AB( long tem1, long tem2 ){ a = tem1; b = tem2; }
     这里定义了函数ABC::AB,注意如之前所说,由于这里的函数定义仅仅只是定义,所以必须在其前面书写类型定义符“{}”以让编译器生成映射元素。但更应该注意这里将成员变量的位置换了,这样b就映射的是0而a映射的是4了,并且还将a、b的类型换成了float,更和a.cpp中的定义大相径庭。但没有任何问题,编译连接成功,a.AB( 10,20 );执行后a.a为0X41A00000,a.b为0X41200000,而*( float* )&a.a为20,*( flaot* )&a.b为10。
     为什么?因为编译器只在当前编译的那个源文件中遵循类型匹配,而编译另一个源文件时,编译其他源文件所生成的映射元素全部无效。因此声明将类型和名字绑定起来,而名字就代表了其所关联的类型的地址类型的数字,而后继代码中所有操作这个数字的操作符的编译生成都将受这个数字的类型的影响。即声明是告诉编译器如何生成代码的,其不仅仅只是个语法上说明变量或函数的语句,它是不可或缺的。
     还应注意上面两个文件中的ABC::ABCD成员函数的声明不同,而且整个工程中(即a.cpp和b.cpp中)都没有ABC::ABCD的定义,却仍能编译连接成功,因为声明并不是告诉编译器已经有什么东西了,而是如何生成代码。


头文件

     上面已经说明,如果有个自定义类型ABC,在a.cpp、b.cpp和c.cpp中都要使用它,则必须在a.cpp、b.cpp和c.cpp中,各自使用ABC之前用类型定义符“{}”重新定义一遍这个自定义类型。如果不小心如上面那样在a.cpp和b.cpp中写的定义不一样,则将产生很难查找的错误。为此,C++提供了一个预编译指令来帮忙。
     预编译指令就是在编译之前执行的指令,它由预编译器来解释执行。预编译器是另一个程序,一般情况,编译器厂商都将其合并进了C++编译器而只提供一个程序。在此说明预编译指令中的包含指令——#include,其格式为#include <文件名>。应注意预编译指令都必须单独占一行,而<文件名>就是一个用双引号或尖括号括起来的文件名,如:#include "abc.c"、#include "C:\abc.dsw"或#include 。它的作用很简单,就是将引号或尖括号中书写的文件名对应的文件以ANSI格式或MBCS格式(关于这两个格式可参考《C++从零开始(五)》)解释,并将内容原封不动地替换到#include所在的位置,比如下面是文件abc的内容。
     struct ABC { long a, b; void AB( long tem1, long tem2 ); };
     则前面的a.cpp可改为:
     #include "abc"
     void main() { ABC a; a.AB( 10, 20 ); }
     而b.cpp可改为:
     #include "abc"
     void ABC::AB( long tem1, long tem2 ){ a = tem1; b = tem2; }
     这时,就不会出现类似上面那样在b.cpp中将自定义类型ABC的定义写错了而导致错误的结果(a.a为0X41A00000,a.b为0X41200000),进而a.AB( 10, 20 );执行后,a.a为10,a.b为20。
     注意这里使用的是双引号来括住文件名的,它表示当括住的只是一个文件名或相对路径而没有给出全路径时,如上面的abc,则先搜索此时被编译的源文件所在的目录,然后搜索编译器自定的包含目录(如:C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include等),里面一般都放着编译器自带的SDK的头文件(关于SDK,将在《C++从零开始(十八)》中说明),如果仍没有找到,则报错(注意,一般编译器都提供了一些选项以使得除了上述的目录外,还可以再搜索指定的目录,不同的编译器设定方式不同,在此不表)。
     如果是用尖括号括起来,则表示先搜索编译器自定的包含目录,再源文件所在目录。为什么要不同?只是为了防止自己起的文件名正好和编译器的包含目录下的文件重名而发生冲突,因为一旦找到文件,将不再搜索后继目录。
     所以,一般的C++代码中,如果要用到某个自定义类型,都将那个自定义类型的定义分别装在两个文件中,对于上面结构ABC,则应该生成两个文件,分别为ABC.h和ABC.cpp,其中的ABC.h被称作头文件,而ABC.cpp则称作源文件。头文件里放的是声明,而源文件中放的是定义,则ABC.h的内容就和前面的abc一样,而ABC.cpp的内容就和b.cpp一样。然后每当工程中某个源文件里要使用结构ABC时,就在那个源文件的开头包含ABC.h,这样就相当于将结构ABC的所有相关声明都带进了那个文件的编译,比如前面的a.cpp就通过在开头包含abc以声明了结构ABC。
     为什么还要生成一个ABC.cpp?如果将ABC::AB的定义语句也放到ABC.h中,则a.cpp要使用ABC,c.cpp也要使用ABC,所以a.cpp包含ABC.h,由于里面的ABC::AB的定义,生成一个符号?AB@ABC@@QAEXJJ@Z(对于VC);同样c.cpp的编译也要生成这个符号,然后连接时,由于出现两个相同的符号,连接器无法确定使用哪一个,报错。因此专门定义一个ABC.cpp,将函数ABC::AB的定义放到ABC.obj中,这样将只有一个符号生成,连接时也就不再报错。
     注意上面的struct ABC { void AB( float ){} };。如果将这个放在ABC.h中,由于在类型定义符中就已经将函数ABC::AB的定义给出,则将会同上,出现两个相同的符号,然后连接失败。为了避开这个问题,C++规定如上在类型定义符中直接书写函数定义而定义的函数是inline函数,出于篇幅,下篇介绍。

OpenClaw简介--windows系统安装OpenClaw 在windows安装OpenClaw实现代替人工操作。步骤流程详细,图文并茂。 阅读详情

相关推荐

延迟相乘叠加求和 DMAS (Field II 仿真代码)

(Delay Multiply and Sum, DMAS)算法,最初是为雷达微波系统设计的,研究者们对 DMAS 波束合成方法进行了修改,并应用超声成像。结果表明,DMAS 波束合成在模拟和实验中的表现都优于传统的延时叠加(Delay and Sum, DAS),这种新方法带来的主要改进是对比度分辨率明显提高(即主瓣和侧瓣更窄),从而增加了动态范围,提高了 B 型超声图像质量。与传统 DAS 相似,DMAS 算法通过对来自超声换能器阵元的信号应用几何计算延迟来聚焦接收到的波束。

weixin_38452364的博客 3083

C++ 变量的定义、声明和初始化

C++ 变量的定义、声明和初始化

程永强 4673

Jlink除了调试还能干啥?用JFlash SPI给W25Q64烧录固件的5个实用技巧

本文深入探讨了Jlink的隐藏功能,特别是通过JFlash SPI高效烧录W25Q64的5个进阶技巧。从硬件连接优化到批量处理脚本,再到数据安全验证,这些技巧能显著提升烧录速度和稳定性,适用于量产环境。文章还提供了详细的参数配置和脚本示例,帮助工程师充分发挥Jlink的潜力。

weixin_29164843的博客 410

C++类的成员函数(在类外定义成员函数、inline成员函数)

类的成员函数(简称类函数)是函数的一种,它的用法和作用和前面介绍过的函数基本上是一样的,它也有返回值和函数类型,它与一般函数的区别只是:它是属于一个类的成员,出现在类体中。它可以被指定为private(私有的)、public (公用的)或protected(受保护的)。 在使用类函数时,要注意调用它的权限(它能否被调用)以及它的作用域(函数能使用什么范围中的数据和函数)。例如私有的成员函数只

Saber_酱 1913

别再让电池充不满!用CN3791芯片设计太阳能充电电路,这几个调试坑我帮你踩了

本文详细解析了使用CN3791芯片设计太阳能充电电路时的常见调试问题及解决方案。从RCS电阻的选择到MPPT电压偏差的修正,再到线路损耗和温度补偿的优化,提供了全面的避坑指南。通过实测数据和优化方案,帮助工程师提升锂电池充电效率,确保太阳能充电电路的稳定性和可靠性。

weixin_42528191的博客 241

(入门向)在Ubuntu22.04.3安装Matlab2021b,以及无法安装在当前目录下的解决办法(见最后)

还有这个/usr/local是只读状态,我试过sudo chmod..去改那个文件的读,结果还是安装不了,我不是这个默认路径,因为它文件夹还是只读,于是我在matlab2021b下创了一个bin,并选上。输入完成后,依次按y,因为里面有三个文件,他会让你确定3次密码,直接yyy跳过即可。你可能会遇到装不下的情况,这个软件占30g,可是你分配给虚拟机就剩10g。,于是我去Downloads下建了一个matlab2021b文件夹,果然好使,3).此时,会提示你输入密码,因为这个rar是有密码的,

harrype的博客 7287

c++函数知识总结及例题代码

1.函数的定义: 返回值类型 函数名(形式参数表) { 语句序列 } (1)各个参数类型重复说明(2)不能出现同名参数(3)在一个函数定义内部不能定义另一个函数,但是可以调用或引用说明(4)内部的所有变量都是局部变量 2.函数的返回值: (1) 通过return语句获得,只要遇到一个return语句,立刻返回到主调函数 (2)函数类型和return不一样时,以函数类型为准 (3)当函数没有返回值时,必须...

m0_64120172的博客 910

基于Python的农业市场价格抓取与供需分析:现代爬虫技术与实战应用

在正式开始爬虫开发之前,我们首先了解爬虫的基本概念和工作原理。爬虫(Web Scraping)是通过编程的方式,自动从互联网上获取信息的技术。它可以帮助我们提取HTML页面中的特定数据,通常用于收集并处理大量信息。发送HTTP请求:爬虫需要向目标网站发送请求,获取网站的HTML页面内容。解析HTML页面:通过HTML解析器对获取的页面内容进行解析,提取其中需要的数据。数据清洗与存储:将提取的数据进行清洗,去除多余的字符或无关内容,然后存储到合适的格式(如CSV文件、数据库等)中。数据分析与可视化。

2201_76125261的博客 1118

C++ Typedef

原文传送 在阅读代码经常会遇到一些复杂的声明和定义,例如: (1) void * (* (*fp1) (int)) [10]; (2) float (* (*fp2) (int, int, float)) (int); (3) typedef double (* (* (*fp3) ()) [10]) (); fp3 a; (4) int (* (*fp4()) [10]) (); 刚看到这些声明或者定义时,一些初学者甚至有一定经验的工

qq_40851561的博客 339

1、vectorCast单元测试常用操作

进入软件主页面,点击file,选择set working directory,随便选择一个保存该项目的目录即可。

weixin_59334478的博客 2157

DeepSeek-OCR安装部署文档和避坑指南,包含大多数人遇到的安装报错问题

DeepSeek-OCR安装部署指南摘要:本文详细介绍高性能OCR工具DeepSeek-OCR的安装流程,支持多语言识别和复杂场景文字提取。系统要求包括Linux/Windows/macOS操作系统,推荐NVIDIA显卡(显存≥6GB)和≥16GB内存。安装步骤涵盖:1)创建conda虚拟环境;2)安装PyTorch等核心依赖;3)解决常见问题如CUDA版本冲突、模型下载慢等。提供GPU内存不足等问题的解决方案,帮助开发者快速部署OCR服务。(149字)

yolo模型训练找我,AI游戏合作找我 2950

c++ 1.2-变量的定义和使用

一起学c++02 变量的作用

qingxueh1的博客 241

Modbus RTU 详解 + FreeMODBUS移植(附项目源码)

本文全面解析Modbus RTU通信协议,详细介绍其报文格式、功能码定义及典型应用场景,并手把手指导如何将FreeMODBUS协议栈移植到嵌入式平台。内容涵盖从底层硬件驱动配置、协议栈移植到主机/从机通信测试的全流程,重点讲解移植过程中的常见问题及解决方案。文章最后提供经过实测的完整项目源码,帮助开发者快速实现稳定的Modbus RTU通信功能。

Bit_Dong的博客 2931

面试:类模版中函数声明在.h,定义在.cpp中,其他cpp引用引入这个头文件,会有什么错误?

当编译器编译一个源文件时,会根据文件中函数的调用去查找函数声明,如果找到了匹配的声明,编译器就认为这个函数存在,并生成一个对外部符号的引用。

GHL284271090的博客 615

怀旧版电脑GBC模拟器

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

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C++函数声明,自定义函数库调用

函数和变量一样,定义和声明是可以分开的,我们一般将只需要包含函数原型的函数声明集中放在头文件中,然后通过预处理命令来调用自定义函数库中的函数,这样可以有效的避免函数重定义的问题。 函数的重定义 //函数的重定义 //作者:分解机226 #include <iostream> using namespace std; int bl(int a,int b) { return a + b; } int bl(int a, int b) { return a + b; } int main

qq_64281750的博客 2582

Camera2Demo

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

C++关于函数声明和定义中参数赋值为0调用问题演示

下面对于C++中方法中参数声明以及定义中的参数赋值为0调用问题,在实际的工作中遇到,便进行了相关的演示处理。如下查看红色部分的差异。 ///////////////////////////////////////////////////////// #include  using namespace std; class T1 { public:          T1(){

sksksksklove的专栏 1966

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

C++模版函数声明和定义分离导致的错误

最近看算法书,想写一些通用的函数实现那些基本的算法,结果第一个就出问题了,如题目说的,C++中把模版函数的声明和定义分别写在了.h和.cpp文件中,导致编译出错。具体是这样的: BasicAlgorithms.h文件: #ifndef BASIC_ALGORITHMS_H #define BASIC_ALGORITHMS_H #include "stdafx.h" #include us

NETALB_CHEN 662

c++ 函数声明和定义

c++ 函数声明和定义

weixin_44880995的博客 221

C++函数声明和定义的原因和作用

<br />原帖地址:<br />http://hi.baidu.com/catro/blog/item/8727c15c4224334ffbf2c052.html<br /><br /><br />声明是告诉编译器一些信息,以协助编译器进行语法分析,避免编译器报错。而定义 是告诉编译器生成一些代码,并且这些代码将由连接器使用。即:声明是给编译器用的,定义是给连接器用的。这个说明显得很模糊,为什么非要弄个声明和定义在 这搅和?那都是因为C++同意将程序拆成几段分别书写在不同文件中以及上面提到的编译器只从

Chris_Magic的学习笔记 2615

c++ 中默认参数的函数声明和定义的注意事项

c++ 中默认参数的函数声明和定义的注意事项。 (1)函数调用在函数定义之前。必须在声明中指出默认参数,否则编译出错。(形参名给出与不给出都可以) int funcc(int x = 7, int y = 8); //给出形参名 //int funcc(int = 7, int = 8); //不给出形参名 int main() { cout<<funcc()<<endl;

oslo---let's go 3361

C++中,参数默认值不能同时出现在函数声明和函数定义当中

函数定义是指在主函数之外单独写一段代码用于执行特定功能的函数,包含返回值类型、名字、形参、函数体。函数声明则只包括返回值类型、名字、形参(形参名可以提供也可以不提供)。为什么有了函数定义还需要函数声明?因为C/C++编译系统是自上而下编译的,如果被调用的函数定义在主函数之后,编译器无法识别被调用的函数,也就无法继续执行后续代码,这个时候就需要在主函数之前进行函数声明,用于提前通知编译器该函数的存在。三、函数定义和函数声明同时出现时,参数默认值只能二选一出现。

2301_81198475的博客 889
上一篇: TCP/IP、Http、Socket的区别
下一篇: 面试智力题
CButtonST
博客等级 码龄16年 42粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值