php内核学习-基本变量zval 和zend_array 和zend_string

PHP的扩展, 可以跟PHP的数组一比 PHP的扩展, 可以跟PHP的数组,因为PHP的数组是使用哈希表的, 所以内存使用比较大, 所以我用红黑树来写了一个dict的结构, 内存使用比PHP的数组少一半以上, 查询速度基本上跟PHP的数组相当, 不过插入速度稍微慢PHP的数组一点. 慢的原因可能是: 1. PHP的数组不用去全局方法表中寻找方法调用, 而扩展函数要去全局的方法表寻找. 2. 红黑树的插入操作比较复杂, 哈希表比较简单, 所以时间稍多一点. 如果内存不足, 而且又想速度快的话, 这个扩展是一个很好的选择 立即下载

1.zval是php变量底层定义的结构,一共16字节

typedef struct _zval_struct     zval;
struct _zval_struct {   
           zend_value        value;     
           union u1;    
           union u2;
};

zval大小

zval 的详细结构如下:
zend_value 是一个联合体 它的大小是8个字节
u1 联合体 4个字节
u2 联合体 4个字节
共16字节

struct _zval_struct {
	zend_value        value;			/* value */
	union {
		struct {
			ZEND_ENDIAN_LOHI_4(
				zend_uchar    type,			/* active type */
				zend_uchar    type_flags,
				zend_uchar    const_flags,
				zend_uchar    reserved)	    /* call info for EX(This) */
		} v;    //4个字节
		//ZEND_ENDIAN_LOHI_4 定义  define ZEND_ENDIAN_LOHI_4(a, b, c, d)    d; c; b; a;
		//typedef unsigned char zend_uchar;
		uint32_t type_info;  //4个字节
	} u1;
	union {
		uint32_t     next;                 /* hash collision chain  用来解决哈希冲突问题,记录冲突的下一个元素位置*/
		uint32_t     cache_slot;           /* literal cache slot  运行时缓存。在执行函数时会优先去缓存中查找,若缓存中没有,会在全局的function表中查找*/
		uint32_t     lineno;               /* line number (for ast nodes) 文件执行的行号,应用在AST节点上 */
		uint32_t     num_args;             /* arguments number for EX(This) 函数调用时传入参数的个数 */
		uint32_t     fe_pos;               /* foreach position  遍历数组时的当前位置*/
		uint32_t     fe_iter_idx;          /* foreach iterator index */
		uint32_t     access_flags;         /* class constant access flags 对象类的访问标志*/
		uint32_t     property_guard;       /* single property guard  防止类中魔术方法的循环调用*/
		uint32_t     extra;                /* not further specified */
	} u2;
};
typedef union _zend_value {
	zend_long         lval;				/* long value */
	double            dval;				/* double value */
	zend_refcounted  *counted;
	zend_string      *str;
	zend_array       *arr;
	zend_object      *obj;
	zend_resource    *res;
	zend_reference   *ref;
	zend_ast_ref     *ast;
	zval             *zv;
	void             *ptr;
	zend_class_entry *ce;
	zend_function    *func;
	struct {
		uint32_t w1;
		uint32_t w2;
	} ww;
} zend_value;

zend_uchar type /* active type */
type代表含义:

#define IS_UNDEF  0
#define IS_NULL  1
#define IS_FALSE 2
#define IS_TRUE  3
#define IS_LONG 4
#define IS_DOUBLE 5
#define IS_STRING 6
#define IS_ARRAY 7
#define IS_OBJECT 8
#define IS_RESOURCE 9
#define IS_REFERENCE 10


struct array

array的数据结构定义在zend_types.h中

typedef struct _zend_array      zend_array;
typedef struct _zend_array      HashTable;
struct _zend_array {
	zend_refcounted_h gc;    //gc 垃圾回收的信息
	union {
		struct {
			ZEND_ENDIAN_LOHI_4(
				zend_uchar    flags,
				zend_uchar    nApplyCount,
				zend_uchar    nIteratorsCount,
				zend_uchar    consistency)
		} v;
		uint32_t flags;
	} u;
	uint32_t          nTableMask;   //散列函数映射元素在arData数组中的下标
	Bucket           *arData;       //存数组元素的头指针,存储的元素结构是Bucket类型的
	uint32_t          nNumUsed;     //已经bucket的个数
	uint32_t          nNumOfElements;    //数组实际存储的元素个数
	uint32_t          nTableSize;     //数组的容量(大小)
	uint32_t          nInternalPointer;
	zend_long         nNextFreeElement;    //下个可用的数值索引,eg:arr[]=1; arr['a']=2; arr[]=3; 则nNextFreeElement=2
	dtor_func_t       pDestructor;
};
typedef struct _Bucket{
	zval	val;		//存储具体的value
	zend_ulong	h;		//哈希值或者数值索引
	zend_string	*key; 	//存储元素的key
}

基本实现

<?php
$a['foo'] = 1;
$a[] = 22;
$a['s'] ='df';
$a['x'] = 4;
echo $a;
33087           z = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC);
(gdb) n
33089           if (Z_TYPE_P(z) == IS_STRING) {
(gdb) p z
$25 = (zval *) 0x7ffff5a1e080     //数组的底层也是zval
(gdb) p *z
$26 = {value = {lval = 140737314694368, 
    dval = 6.9533472278435683e-310, counted = 0x7ffff5a624e0, 
    str = 0x7ffff5a624e0, arr = 0x7ffff5a624e0, 
    obj = 0x7ffff5a624e0, res = 0x7ffff5a624e0, 
    ref = 0x7ffff5a624e0, ast = 0x7ffff5a624e0, 
    zv = 0x7ffff5a624e0, ptr = 0x7ffff5a624e0, 
    ce = 0x7ffff5a624e0, func = 0x7ffff5a624e0, ww = {
      w1 = 4121306336, w2 = 32767}}, u1 = {v = {type = 7 '\a', 
      type_flags = 20 '\024', const_flags = 0 '\000', 
      reserved = 0 '\000'}, type_info = 5127}, u2 = {next = 0, 
    cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, 
    fe_iter_idx = 0, access_flags = 0, property_guard = 0, 
    extra = 0}}
//u1.v.type=7 是数组类型

(gdb) p *z.value.arr 
$27 = {gc = {refcount = 1, u = {v = {type = 7 '\a', 
        flags = 128 '\200', gc_info = 0}, type_info = 32775}}, 
  u = {v = {flags = 26 '\032', nApplyCount = 0 '\000', 
      nIteratorsCount = 0 '\000', consistency = 0 '\000'}, 
    flags = 26}, nTableMask = 4294967288, arData = 0x7ffff5a68660, 
  nNumUsed = 4, nNumOfElements = 4, nTableSize = 8, 
  nInternalPointer = 0, nNextFreeElement = 1, 
  pDestructor = 0x8c6f9c <_zval_ptr_dtor_wrapper>}
//nTableSize = 8 标识$a中数组的容量是8,   nNumUsed = 4, 已经用了4个 nNumOfElements = 4,实际用了4个, nNextFreeElement = 1,因为$a[]=22用掉一个,默认重0开始的。

(gdb) p z.value.arr.nTableMask 
$28 = 4294967288
(gdb)p (int32_t)z.value.arr.nTableMask 
29 = -8
// nTableMask  = -nTableSize

 
(gdb) p z.value.arr.arData[0]
$30 = {val = {value = {lval = 1, dval = 4.9406564584124654e-324, 
      counted = 0x1, str = 0x1, arr = 0x1, obj = 0x1, res = 0x1, 
      ref = 0x1, ast = 0x1, zv = 0x1, ptr = 0x1, ce = 0x1, 
      func = 0x1, ww = {w1 = 1, w2 = 0}}, u1 = {v = {
        type = 4 '\004', type_flags = 0 '\000', 
        const_flags = 0 '\000', reserved = 0 '\000'}, 
      type_info = 4}, u2 = {next = 4294967295, 
      cache_slot = 4294967295, lineno = 4294967295, 
      num_args = 4294967295, fe_pos = 4294967295, 
      fe_iter_idx = 4294967295, access_flags = 4294967295, 
      property_guard = 4294967295, extra = 4294967295}}, 
  h = 9223372037048267657, key = 0x7ffff5a6db40}
//取第0个元素

(gdb) p (int32_t)$30.h | $34
$36 = -7
// nindex =  bucket.h |  (int32_t)z.value.arr.nTableMask   ,$a['foo'] 对应的值存储的索引下标是-7
(gdb) p ((uint32_t*)(z.value.arr.arData))[(int32_t)(-7)]
$37 = 0  //算出的0是对应bucket的位置,与上边我们取的数组的下边一致

(gdb) p z.value.arr.arData[1]
$39 = {val = {value = {lval = 22, dval = 1.0869444208507424e-322, 
      counted = 0x16, str = 0x16, arr = 0x16, obj = 0x16, 
      res = 0x16, ref = 0x16, ast = 0x16, zv = 0x16, ptr = 0x16, 
      ce = 0x16, func = 0x16, ww = {w1 = 22, w2 = 0}}, u1 = {v = {
        type = 4 '\004', type_flags = 0 '\000', 
        const_flags = 0 '\000', reserved = 0 '\000'}, 
      type_info = 4}, u2 = {next = 4294967295, 
      cache_slot = 4294967295, lineno = 4294967295, 
      num_args = 4294967295, fe_pos = 4294967295, 
      fe_iter_idx = 4294967295, access_flags = 4294967295, 
      property_guard = 4294967295, extra = 4294967295}}, h = 0, 
  key = 0x0}
(gdb) p (int32_t)$39.h | $34
$40 = -8
(gdb) p ((uint32_t*)(z.value.arr.arData))[(int32_t)(-8)]
$41 = 2
//   2 不等于 上边的下标1,这时说明在数组中别的key和1这个位置映射的索引数组的位置冲突,这个时候去取z.value.arr.arData[2].u2.next,一次类推直到取到和上边的下标对应数值
(gdb) p z.value.arr.arData[2]
$42 = {val = {value = {lval = 140737314741312, 
      dval = 6.9533472301629101e-310, counted = 0x7ffff5a6dc40, 
      str = 0x7ffff5a6dc40, arr = 0x7ffff5a6dc40, 
      obj = 0x7ffff5a6dc40, res = 0x7ffff5a6dc40, 
      ref = 0x7ffff5a6dc40, ast = 0x7ffff5a6dc40, 
      zv = 0x7ffff5a6dc40, ptr = 0x7ffff5a6dc40, 
      ce = 0x7ffff5a6dc40, func = 0x7ffff5a6dc40, ww = {
        w1 = 4121353280, w2 = 32767}}, u1 = {v = {type = 6 '\006', 
        type_flags = 0 '\000', const_flags = 0 '\000', 
        reserved = 0 '\000'}, type_info = 6}, u2 = {next = 1, 
      cache_slot = 1, lineno = 1, num_args = 1, fe_pos = 1, 
      fe_iter_idx = 1, access_flags = 1, property_guard = 1, 
      extra = 1}}, h = 9223372036854953496, key = 0x1398fd0}



Altium Designer 16安装教程(Windows11、小白教程) Altium Designer 16在Windows11中的超详细安装教程 阅读详情

相关推荐

用OpenCV+ROS实现焊接机器人智能纠偏:线激光视觉的算法调参全流程

本文详细介绍了基于OpenCV和ROS的焊接机器人智能纠偏系统全流程。通过线激光视觉系统实时感知焊缝,重点解析了抗干扰图像预处理、改进的Steger算法提取激光条纹中心线,以及从2D像素到机器人基坐标系的完整坐标变换。该系统为应对焊接飞溅、弧光等复杂工况,实现高精度实时路径纠偏提供了从算法优化到工程集成的完整解决方案。

vodka的博客 158

PHP7数组(zend_array)的实现

PHP7数组的实现 1 | 基本概念 1.1数组的语义 1.PHP的数组是一个字典,存着键-值(key-value) 2.PHP数组是有序的。即插入有序且遍历时也是有序的。 PHP使用HashTable来存储键值对,但不能保证其有序性,所以需要做一些额外的设计来保证有序性 1.2数组的概念 zend_array 对应的是HashTable 但PHP数组中分为package array 和hash array所以通过需要通过的两个hash函数来保留的下标的值。 [外链图片转存失败,源站可能有防盗链机制,建

onefiter的编程之路 629

408——计算机组成原理(持续更新)

小数点前的0代表正数,1代表负数。

qq_55202378的博客 1721

php扩展库后门,编写基于PHP扩展库的后门

0x00 前言今天我们将讨论编写基于PHP扩展库的后门。通常来说,大部分入侵者都会在脚本中留下自定义代码块后门。当然,这些东西很容易通过源代码的静态或动态分析找到。利用PHP扩展库的好处显而易见:很难寻找绕过disable_functions选项有能力控制所有的代码访问代码执行的API但是我们需要有编辑PHP配置文件的能力。0x01 细节//【译者注:用linux两条命令搞定了,何必windows...

weixin_31184569的博客 296

Android 13高通平台CTS camera部分fail项修改(续)

接着上一篇,有几个提了case高通也分析了很久的fail项,其中最离谱的是问题1,第一个接手case的人反反复复处理、内部排查踢皮球、要求log,折腾了很久,最终就给出个解不了的结论。后面还是靠着自己发现了一些蛛丝马迹,并且换了个case接手人才最终解决。

hkj887tg的博客 2059

离线路径规划服务Graphhopper

离线路径规划服务Graphhopper 本文主要探索使用Graphhopper搭建离线路径规划服务,需要掌握一定的JAVA基础环境配置的知识 文章目录离线路径规划服务Graphhopper前言一、Graphhopper是什么?二、使用步骤1.下载Graphhopper2.从OpenStreetMap下载路图数据3.安装Graphhopper所需环境4.修改配置5.启动Graphhopper总结 前言 在外网环境中可以使用百度、高德等第三方的sdk用以实现路径规划的功能,由于项目的需要,在离线环境中需要使

Sysdark的博客 7557

PHP 的 _zend_array ,知识体系一共包含哪些部分?

咱们把这个想象成一个“神奇的玩具收纳箱”,专门用来装 PHP 里的数组玩具——就像你收拾积木、小汽车那样,这个收纳箱有特别的办法把所有玩具摆得整整齐齐,还能很快找到想要的那个。

长风破浪会有时的博客 634

YOLO11后处理优化 | 引入DIoU-NMS替代传统NMS,解决高重叠目标误删,召回率大幅提升

YOLO11模型在密集目标场景下存在NMS后处理导致的漏检问题。本文提出采用DIoU-NMS替代传统NMS,通过引入中心点距离信息,有效区分重叠但不同的目标,提升召回率。文章详细分析了传统NMS的三大局限性,对比了Soft-NMS和DIoU-NMS的优劣,并给出在YOLO11中实现DIoU-NMS的完整代码方案。该方法特别适用于安防监控、自动驾驶等目标密集场景,能够在不显著增加计算量的情况下显著改善检测效果。

2601_95807009的博客 150

数据结构---array

保存一个HashTable结构体 /* Zend/zend_type.h */ typedef struct _zend_array HashTable; //这个结构体64位平台占56个字节. struct _zend_array { zend_refcounted_h gc; //引用计数信息,与字符串相同 union { struct {

凯子 363

基于图像形态学处理的交通灯检测识别matlab仿真

图像形态学处理是基于数学形态学的理论,利用结构元素(如矩形、圆形等)对图像进行处理,通过将结构元素与图像进行特定的逻辑运算,来提取图像中的目标特征、去除噪声、改善图像质量等。在交通灯检测识别中,主要利用交通灯的颜色、形状等特征,通过形态学操作突出这些特征,抑制背景和噪声干扰,从而实现对交通灯的准确检测和识别。图像采集与预处理采集:通过安装在车辆或道路上的摄像头获取交通场景图像。灰度化:将彩色图像转换为灰度图像,减少数据量,便于后续处理。

平时工作较为繁忙,私信消息一般晚上回复,谢谢大家~~ 160

基于深度确定性策略梯度的永磁同步电机强化学习控制方法

本文提出了一种基于深度确定性策略梯度(DDPG)的永磁同步电机(PMSM)电流内环智能控制方法。首先建立了PMSM在d-q坐标系下的数学模型,分析了传统矢量控制双闭环系统中PI控制器的局限性。针对电流内环控制问题,设计了包含电流跟踪误差、转速信息和历史控制量的状态空间,将电压输出作为动作空间,并构建了兼顾跟踪精度和响应速度的奖励函数。通过DDPG算法训练智能体,使其能够自适应调整控制策略。仿真结果表明,与固定参数的PI控制器相比,DDPG控制器在动态响应速度和抗干扰能力方面具有明显优势,为PMSM高性能控制

huanghm88的专栏 103

PHP的zval = zend_array = zend_object?

结构作用类比zval通用变量容器,用于存储任何 PHP 变量的值和类型信息(包括标量、数组、对象、资源等)≈ 一个“万能快递盒”,盒子上贴标签(类型),里面装东西(值)zend_arrayPHP 数组的底层实现,本质是一个优化的哈希表(HashTable的别名)≈ 一个“带目录的文件柜”,用于组织多个zvalPHP 对象的底层实现,包含类信息、属性表、句柄等≈ 一个“带说明书的产品”,说明书是类,产品状态是属性✅关键结论zval是所有变量的外层包装。zend_array和是。

长风破浪会有时的博客 618

企业级大数据平台的数据网格(Data Mesh)转型之路

随着企业数字化转型的深入,传统大数据平台面临数据孤岛化、治理成本高、业务响应慢等核心痛点。数据网格作为一种新兴的分布式数据管理架构,通过领域驱动设计(DDD)、数据产品化和联邦治理模式,为企业提供了打破数据壁垒、提升数据生产力的全新路径。本文聚焦企业级数据平台从传统架构(数据湖/数据仓库)向数据网格转型的关键技术、实施步骤和组织配套,涵盖技术架构设计、核心算法实现、项目实战案例及工具链推荐。背景介绍:定义转型目标、术语体系与核心挑战核心概念与联系:解析数据网格四大支柱及技术架构图谱核心算法原理。

AI 领航者的博客 1083

跟厂长学PHP内核7(六):变量之zval

记得网上流传甚广的段子“PHP是世界上最好的语言”,暂且不去讨论是否言过其实,但至少PHP确实有独特优势的,比如它的弱类型,即只需要$符号即可声明变量,使得PHP入手门槛极低,成为大家所青睐的Web服务端语言。那么它的变量是如何实现的呢?我们今天就来学习一下PHP的基本变量。 一、引言 PHP的变量存储在zval结构体中,在执行阶段中编译为op_array时就能看到zval的身影。结构体定义在...

ahilll的博客 131

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

PHP7 数组的实现

3). 若此时插入第3个bucket,与第1个和第2个冲突,那么用同样的方式,令nIndex = -3的位置值为3,同时将第3个bucket中zval里面的u2.next值置为2。1). 插入第1个bucket,对应nIdex为-3,那么此时nIndex = -3的位置值为1。2). 若此时插入第2个bucket,与第1个冲突,也就是对应的nIndex也为-3。rehash对应源码中的zend_hash_rehash(ht)方法。rehash不重新申请内存,整个过程是在原有结构上做聚合调整。

weixin_40398522的博客 1322

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

php实现变量值呼唤,php变量是如何实现的

php变量的实现方法:首先声明一个zval指针,并申请一块内存;然后通过【ZVAL_STRING】宏将值设置为bar;最后就是将这个zval加入到当前的符号表里去,并将其label定义成foo。【相关学习推荐:php图文教程】php变量的实现方法:简介在官方的PHP实现内部,所有变量使用同一种数据结构(zval)来保存,而这个结构同时表示PHP中的各种数据类型。 它不仅仅包含变量的值,也包含变量的...

weixin_30676505的博客 93

Camera2Demo

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

用Rust重写PHP虚拟机:从Zend Engine原理到AI辅助实现

虚拟机作为现代编程语言的核心执行引擎,负责将高级语言代码转换为底层机器可执行的指令序列。其工作原理通常涉及词法分析、语法解析、中间代码生成和指令执行等关键环节,通过模拟计算机的寄存器、栈和内存管理模型来实现跨平台运行。在系统级编程领域,Rust语言凭借其所有权模型和零成本抽象特性,为构建高性能、内存安全的系统软件提供了新的技术方案。将Rust应用于虚拟机开发,不仅能提升执行效率,还能从根本上避免内存泄漏和数据竞争等常见问题。这一技术组合特别适用于需要高并发和高可靠性的应用场景,例如Web服务器、实时数据处理

weixin_34075268的博客 376

PHP内核探索之变量(1)Zval

作为数据的容器,我们常常需要跟变量打交道,不管这个变量是数字、数组、字符串、对象还是其他,因而可以说变量是构成语言的不可或缺的基础。本文是PHP内核探索之变量的第一篇,主要介绍zval的基本知识,包括如下几个方面的内容: Zval的基本结构 查看zval的方法:debug_zval_dump和xdebug Zval的原理,COW等 由于写作仓促,难免会有错误,欢迎指出。 一、...

weixin_30276935的博客 63

跟厂长学PHP7内核(六):变量之zval

记得网上流传甚广的段子“PHP是世界上最好的语言”,暂且不去讨论是否言过其实,但至少PHP确实有独特优势的,比如它的弱类型,即只需要$符号即可声明变量,使得PHP入手门槛极低,成为大家所青睐的Web服务端语言。那么它的变量是如何实现的呢?我们今天就来学习一下PHP的基本变量。 一、引言 PHP的变量存储在zval结构体中,在执行阶段中编译为op_array时就能看到zval的身影。结...

weixin_30906425的博客 325

【PHP内核学习】变量和数据类型

php内核中所有的变量使用同一种数据结构zval来保存,而这个结构同时表示php中各种数据类型,它不仅仅包含变量的值,也包含变量的类型。这就是php弱类型的核心。

wusuopuBUPT的专栏 1770

php内核源码解析=实战项目——亲手改PHP内核

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>15-JavaScript-商品展示</title> <style> *{ margin: 0; padding: 0; } div{ widt

qq_37805832的博客 587

php7 扩展 类,PHP7扩展开发之类型处理

前言这次,我们将演示如何在PHP扩展中如何对类型进行一些操作。如,判断变量类型。要实现的PHP代码如下:分别获取string 和 array的长度。代码基础代码这个扩展,我们将在say扩展上增加 get_size方法。say扩展相关代码大家请看这篇博文。 PHP7扩展开发之hello word文中已经详细介绍了如何创建一个扩展和提供了源码下载。实现get_size方法get_size方...

weixin_42566424的博客 200

PHP7内核剖析 学习笔记 第三章 数据类型

type_info实际是将v结构的4个成员组合到了一起,v中的成员各站一个字节,总共4个字节,type_info也是4个字节,每个字节对应v的一个成员,可直接通过type_info位移获取v成员的值。如果发现中间映射表中要设置的位置已经被之前插入的元素占用了(值不等于初始化的-1),那么会把已经存在的值保存到新插入的Bucket中(实际是将Bucket的zval成员的u2.next指针指向已经存在的Bucket),然后将中间映射表中的值更新为新Bucket的存储位置,即每次都会把冲突的元素插到开头。

tus00000的博客 1187

Rust构建PHP虚拟机:AI辅助的编译原理与系统编程实践

编译原理是计算机科学的核心基础,涉及将高级语言转换为可执行代码的完整技术链。其核心流程包括词法分析、语法解析、中间表示生成和代码执行等阶段,这些技术构成了现代编程语言运行时的基石。从技术价值看,深入理解编译原理不仅能提升对语言特性的掌控力,还能为性能优化、安全加固和语言设计提供底层支撑。在应用场景上,编译原理技术广泛应用于数据库查询优化、模板引擎设计、领域特定语言开发等工程实践。本文以PHP虚拟机开发为具体载体,通过Rust语言实现从词法分析到字节码执行的全流程,并重点探讨了AI辅助在代码生成、测试用例编写

weixin_30920853的博客 356
上一篇: sublime 安装扩展遇到的问题
下一篇: php 排序-冒泡
龘麤三思
博客等级 码龄10年 11粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值