DebuggingTechniques

PCIe-4.2.3.2 Processing of Ordered Sets During Flit Mode Data Stream 动态门控检测(Gated Detection):绝不能在非预定时钟周期进行全时段 OS 匹配。这能节省大量动态功耗。并行容错比较器:必须实现 64-bit 宽的容错匹配器(5/8 表决),这对时序(Timing)要求较高,需要考虑多级流水线(Pipeline)设计。变长状态机(Variable Length FSM):SKP 子状态机必须具有Count_8B计数器,并且要有上限强退保护(Max Count = 6)。控制信号广播。 阅读详情

http://www.cocoadev.com/index.pl?DebuggingTechniques


DebuggingTechniques

last edited December 27, 2011 10:34:53 (82.95.218.199)
CocoaDev is sponsored by: Panic: Shockingly good Mac software!

CocoaGlossary:Concepts (Cocoa)ExceptionHandling

See also Apple's technote at http://developer.apple.com/technotes/tn2004/tn2124.html, which contains a wealth of info about API-specific techniques and tools.


Code Flow Tracing

NSLog(@"%s", __PRETTY_FUNCTION__, nil) will display the prototype for the currently executing function/method in the console log. It is useful for "tracer" style debugging.

A quick way to comment out NSLog statements (if your code becomes littered by them) is to get into the habbit of always having at least one tab in front of any NSLog statement. This allows you to find and replace "<space><space>NSLog" with "<space><space>//NSLog" (XCode's default setting is to replace tabs with four spaces). If you have an NSLog statement that is part of an if/else statememt then only use one space to separate the NSLog statement from any code in front of it (to avoid altering any logic).

-(void)someMethod {
<space><space><space><space>NSLog(@"someMethod entered");
<space><space><space><space>if<space>(someCondition)<space>NSLog(@"condition met");
<space><space><space><space>else<space>NSLog(@"condition not met");
}

To make the NSLog statements active again you just have to find and replace "<space><space>//NSLog" with "<space><space>NSLog"

NOTE: A better way to comment and uncomment NSLog or any other desired text is to use Project Builder's regular expression find. Be sure to limit the location of where to search for text to "this project, no frameworks". In the Find text field type (NSLog([ \r\n\t\(]+)), and in the Replace text field type // \1. To uncomment your NSLogs?: in the Find text field type // (NSLog([ \r\n\t\(]+)), and in the Replace text field type \1.

Or, my favorite approach:

Put the following in a header, e.g. DebugUtils?.h:

#if MY_DEBUG_FLAG
#define DEBUG_OUTPUT( a )         NSLog( a )
#define DEBUG_OUTPUT1( a, b )     NSLog( a, b )
#else
#define DEBUG_OUTPUT( a )         // (a)
#define DEBUG_OUTPUT1( a, b )     // (a,b)
#endif

and then to add -DMY_DEBUG_FLAG=1 to the OTHER_CFLAGS of your "Debug" build style in ProjectBuilder (click the = to turn it into += so it doesn't overwrite any other flags). This will automatically define the debug flag and you'll get debugging output for debug builds while release builds ("deployment") will have the macro expand to no code at all. This requires a separate macro for each number of parameters, though, as the C Preprocessor doesn't support va_arg macros yet... (UliKusterer 2003-10-06)

With C99, you can make portable varargs macros:

#define DEBUG_OUTPUT(fmt, ...) NSLog(fmt, ## __VA_ARGS__)
That #define will work for any number of arguments to NSLog. (MikeAsh 2004-03-13)

Worth noting: The introduction to the example above said 'tabs', but the example itself used spaces. Tabs aren't spaces. The technique described will work either way; just use a tab instead of however-many spaces. And you should be indenting your code anyway. --boredzo (2004-09-20)

Also worth noting: Speaking of NSLog, check out this excellent article: "A Better NSLog" at http://www.borkware.com/rants/agentm/mlogor its follow up at Hopeless Geek ( http://www.hopelessgeek.com/2005/11/18/better-logging ) Simple to implement and will provide file, function and line number of the log call.


Backtrace All Threads

"t a a bt" in gdb's console will get you a backtrace of all threads, not just the current one. (The full command is "thread apply all backtrace", but gdb will accept abbreviations.)


Environment Variables That Affect Your App

Read /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDebug.h for interesting environment variables you can set to get extra debugging information. NSZombieEnabled, for example, will tell you if you are sending messages to objects you have released. On 10.4 and below, an important exception is that NSZombie does not work with any 'toll free bridged' class. So NSZombie won't help you with catching over releases of NSStrings, etc. CFZombieLevel however will help in those cases. On 10.5, NSZombie works with all classes, so CFZombieLevel is not needed.

One way to set this variable is to select "Edit Active Target" from the Project menu, choose the "Executables" tab, then the "Env Vars" tab. Add a variable called NSZombieEnabled, with value YES.


Breaking on Exceptions

Note: "Double-Click for Symbol" no longer exists in XCode 4

You can break into the debugger whenever an exception is raised. Go to the Breakpoints window in Xcode, and double click "Double-Click for Symbol". Add a breakpoint for "-[NSException raise]" and for "objc_exception_throw" to the breakpoints list.

You can also accomplish this from the gdb console by entering "b -[NSException raise]" or "fb -[NSException raise]", and then the same command for objc_exception_throw. The latter is not frequently encountered in Tiger but is essential in Leopard, as much of the internal Cocoa code has moved to @throw which bypasses -[NSException raise] and will not trigger a breakpoint set there. You might want to add these to your ~/.gdbinit file.

When stopping at objc_exception_throw the exception object is stored in $edx ($rax on x86_64), you can print information about the exception in the gdb console like so:

(gdb) po [$eax className]
NSException
(gdb) po [$eax name]
NSAccessibilityException
(gdb) po [$eax reason]
<object returned empty description>
(gdb) po [$eax userInfo]
{
    NSAccessibilityErrorCodeExceptionInfo = "-25205";
}


Talking to Objects

NSLog(@"%@", anyObject) will send -description to anyObject, and print the results. This replaces the 'printf' method of debugging from C. Cocoa collection and data classes implement -description to print out a human-readable dump of the object's contents; most Cocoa classes use the NSObject default implementation of -description which prints the object class name and address in memory. So, for example, if anyObject is a dictionary, the output will be a list of the key-value pairs in the dictionary. (The values will each get sent -description as well, and so on...). Note, however, that if the object is being observed by way of KVO, the -description method is broken, this is due to the 'isa-swizzling' used under the hood.

You can do the same thing from the gdb console: type "po anyObject".

If you are really feeling like a daredevil, you can even call arbitrary Objective-C code from gdb! For example, "po [[array objectAtIndex:2] objectForKey:@"foo"]". Watch out though -- if the code throws an exception you might find yourself unable to continue debugging. But you can avoid that by tweaking a parameter in gdb: "set unwindonsignal on" before you do it. You might want to add that to your ~/.gdbinit file.

[NSObject description] is not that good at times, i highly depend on CFShow?() for clear details , for example consider the following :

	NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:NULL];
	CFShow([dict class]);
	CFShow([[NSDictionary dictionaryWithDictionary:dict] class]);
it returns : NSFileAttributesNSCFDictionary ?
CFShow(dict);
CFShow([NSDictionary dictionaryWithDictionary:dict]);  
show you that there is a difference in the object , by contrast if you do just CFShow ?([dict description]); and CFShow ?([[ NSDictionary dictionaryWithDictionary:dict] description]) they show the same thing --VladAlexa ?


Tracking down MemoryLeaks

The page for ObjectAlloc has an introduction into using that application to find MemoryLeaks.


Implement - (NSString *)description for Your Classes

A typical way to implement the -description method is:

// Description method for PersonObject
- (NSString *)description
{
    NSString *desc = [NSString stringWithFormat:@"%@\n\ 
                                                  \tName: %@\n\ 
                                                  \tAge: %i\n\ 
                                                  \tOccupation: %@\n\ 
                                                  \tSpouse: %@",
                         [super description], // grab output from the default
                         [self name],         // name returns a string
                         [self age],          // age returns an int
                         [self occupation],   // occupation returns a string
                         [self spouse]];      // spouse returns a person object
	return desc;
}

Now NSLog(@"%@", personObjInstance, nil) will print out the string you just formed. Be sure to return an autoreleased string. Remember, if the object is being observed using KVO an implementation of the -description selector may obscure your own, this is due to the 'isa-swizzling' used under the hood.

Is it possible to use the keypath "self" to get a reference to the real object, so that -description will work?


Stack Traces in ObjC

With a bit of code, you can have StackTraces in ObjC - just click on the link to see how.


Before working too hard fixing a problem where you think it is, make sure the problem is actually there (particularly with crashers) I'm a fan of temporarily #ifdefing out code and seeing if it still crashes. if it crashes in the same place, you can pretty much exclude the code you've just #ifdef'd out and not spend any time looking at it. I help a friend this week track down a retain/release issue, and he was fretting for a long time over some iterator stuff, when the real problem was an init call several lines back releasing an autoreleased object. By #ifdefing out the iterator stuff, I knew not to waste any time look at it.

Also, being able to reproduce the problem at-will is a very powerful tool. If you can make your app crash in 5 steps (vs "I randomly click and eventually it dies"), it then becomes much easier to narrow in on the problem.

My general technique when faced with a problem is to a) try to reproduce it reliably then b) eliminate as much other code from my consideration, then c) unleash debuggers and CavemanDebugging to narrow in on the problem.

++MarkDalrymple


If gdb gets confused and starts spitting messages like "warning: pre-compiled symbol file random_symbol_file.syms out of date", the situation can be remedied by doing the following in the terminal:
cd /usr/libexec/gdb
sudo ./cache-symfiles 

++TimothyKukulski


Assembly code

At times, you may want to see what parameters get passed to one of Apple's methods. An assembly-language method. Well, it is possible. When a method is called, the PPC registers are assigned as follows:

  • $r3 — self
  • $r4 — The selector
  • $r5-$r10 — Parameters
This is not the entire story if the method has a variable argument list, or takes floating-point, vector, structure (i.e. NSRect), or long long parameters. See http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/2rt_powerpc_abi/chapter_9_section_5.html for exceptions and details.

So if you happen to know that the first parameter (in $r5) is an ObjC instance, you can print it out at the (gdb) prompt by typing:

po $r5
or call other methods by typing something like:
print (int)[$r5 hash]

Note that assembly-language routines will typically move these registers around ASAP, so watch out for that. The assembly statement will be "mr <to>,<from>".

—DustinVoss

The above works on PowerPC, but not on 32-bit Intel. On 32-bit Intel, arguments to a function are passed on the stack, not in registers. 64-bit Intel restores sanity to the equation by passing arguments in registers.

Quoth the almighty Technical Note TN2124, Mac OS X Debugging Magic:

On PowerPC, a good rule of thumb is that the first parameter is in GPR3 (General Purpose Register 3), the second parameter is in GPR4, and so on. The GDB syntax for these is $r3, $r4, and so on. On return, any function result is in GPR3 ($r3).

On Intel, there are two rules of thumb.

  • If you've stopped at the first instruction of a routine, the first parameter is at 4 bytes above the stack pointer, the second parameter is 8 bytes above the stack pointer, and so on. The GDB syntax is *(int *)($esp+4), *(int *)($esp+8), and so on.

  • If you've stopped elsewhere in the routine (after the frame has been created), the first parameter is at 8 bytes above the frame pointer, the second parameter is 12 bytes above the frame pointer, and so on. The GDB syntax is *(int *)($ebp+8), *(int *)($ebp+12), and so on.
In both Intel cases, any function result is in register EAX ($eax).


Interpreting Crash Logs

Apple's tech note TN2123 describes interpreting the output of Crash Reporter. http://developer.apple.com/technotes/tn2004/tn2123.html

One tip: the atos command-line utility described in the tech note will not work if you have Zerolink enabled.


Debugging Cocoa Exceptions in Codewarrior --

If you are using the Codewarrior debugger instead of XCode, it's not obvious how to drop into the debugger on an exception. You can create a category on NSException to always drop into the debugger and go back up in the stack to see what happened. Unfortunately, since you are replacing the 'raise' method, you won't see the helpful message that gets printed to the log. Does anyone know a better way to get the Codewarrior Debugger to break and still print the helpful log information?

@implementation NSException (StopOnException)

-(void)raise
{
	NSLog(@"%@", self, nil);
	assert (0);	
}

@end


Event Handling

See NSTraceEvents


see also DebuggingTechniquesDiscussion

 


Unity Shader学习笔记/Urp/水墨风效果 Unity Shader学习 阅读详情

相关推荐

【自动驾驶】汽车智能驾驶计算芯片

本文介绍汽车智能驾驶计算芯片的软硬件要求、 可靠性和安全性要求、 性能要求,和相应的试验方法。除了用于汽车智能驾驶, 其他领域的计算芯片可参照执行。

Mr.Cssust的博客 2631

<Debugging Techniques> LDD3 学习笔记

Debugging Techniques 内核debug的挑战:                    Kernel programming brings its own, unique debugging challenges. Kernel code can not be easily executed under a debugger, nor can it be eas

Jason Leaster | Rebuilding the tower of babel 1830

STM32N6570-DK ISP调试

将下载线接入STLINK V3EC接口,将BOOT1拨码拨至右边,即将其置为H,上电或已经上电的按复位,打开STM32CubeProgrammer,设置start address:0x70000000。板子消耗电流较大,即使缩短数据线接了USB供电依然不能正常点亮显示屏,最终通过板上CN2端子加了外部5V供电,仍然需要560mA的外部电流。3.烧录bin文件:STM32N6_ISP_IQTune_App_revC01-v1.1.0-trusted.bin。

liu的博客 1063

Debugging Techniques [LDD3 04]

kernel相较于user,debug起来更加困难,原因有很多,比如kernel中代码的执行是并发的,靠event来驱动;而且kernel一旦出现了bug,很容易把整个系统搞挂,导致后面的现场无法trace,本章就介绍了一些kernel中的debug技巧。 Debugging Support in the Kernel kernel的发行版都是production code,也就是说里面包含的...

scutth的专栏 223

【IC】Redhawk-SC输入件配置

Redhawk sc

u011808788的博客 1776

国产麒麟系统下Kettle安装避坑指南:解决aarch64架构不支持问题

本文详细解析了在国产麒麟系统上部署Kettle时遇到的aarch64架构不支持问题,提供了从获取适配的SWT库、修改启动脚本到生产环境调优的完整解决方案。文章重点解决了ARM架构与Java GUI工具的兼容性挑战,并分享了内存配置、字体显示及Carte服务部署等实战经验,助力用户在国产化环境中稳定运行ETL流程。

weixin_29197835的博客 559

(转)DebuggingTechniques

转自:http://www.cocoadev.com/index.pl?DebuggingTechniques See also Apple's technote athttp://developer.apple.com/technotes/tn2004/tn2124.html, which contains a wealth of info about API-specific tec...

weixin_30568715的博客 159

OI 生涯回忆录 《Pilgrimage》

前言 于 NOI2020 后写下本文。 本文简单提及了在写作时尚能回忆起来的,在我的 OI 生涯中对我的影响重大的人、事、比赛等。 写作本文,旨在在回忆允许的范围内,对 OI 生涯进行一定程度上的梳理,总结。 开端 入门 我最早接触计算机程序设计,是在小学。 那时候,我的数学成绩不错,就被老师推荐去学习编程。 就这样,我在局前街小学的何静老师的指导下,走上了编程的道路。 小学时的编程,与其说是 “竞赛” ,不如说是 “兴趣班” 。 当时,包括我在内,很多小孩子天性是浮躁的。支撑我对着无聊的代码学下去的,并不

cz_xuyixuan的博客 1万+

android studio 运行出现Application installation failed

Installation failed with message Invalid File: C:\Users\yqekzb\Desktop\BiaoQingBao\app\build\intermediates\split-apk\debug\slices\slice_9.apk. It is possible that this issue is resolved by uninstalli...

u012763405的博客 745

23 RAG 为什么答不准:召回、分块、排序的常见坑

RAG 答不准时,不要先怪模型。本文把常见失败拆成召回不到、召回不准、分块不完整、排序靠后、上下文污染和生成不忠实六类,并给出从 Top-K 检查到评估集的排查流程。

老于的笔记的专栏 245

Vue3 - [兼容PC和手机H5] 详细监听浏览器刷新 / 关闭 / 前进后退事件,用户点击关闭和刷新页面前 “拦截“ 操作并弹出提示框(实时监听用户关闭或刷新网页,触发时文字提醒并执行自定义操作)

vue3监听页面关闭和刷新,vue3中如何监听页面刷新和关闭事件,vue3中监听浏览器窗口关闭事件,并在窗口关闭进行操作,vue3怎么只在某个页面监听,其他页面不监听,vue3监听刷新和关闭怎么离开页面时注销释放,vue3怎么阻止浏览器前进和后退并提示,页面跳转离开后依旧可以监听到刷新和关闭,vue3怎么知道用户关闭了网页,vue3如何监听刷新网页操作并截断,vue3移动端手机h5网页手机网站监听浏览器刷新关闭,vue3当页面关闭或刷新时怎么提示用户离开不保存数据,vue3项目监听浏览器窗口或标签页关闭,并

🏆 前端领域优质创作者 1万+

Stack Sorting CodeForces - 911E (思维+单调栈思想)

Let's suppose you have an arraya, a stacks(initially empty) and an arrayb(also initially empty). You may perform the following operations until bothaandsare empty: Take the first element ...

weixin_30420305的博客 116

Camera2Demo

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

deprecated pixel format used, make sure you did set range correctly

deprecated pixel format used, make sure you did set range correctly 不推荐使用的像素格式,请确保设置的范围正确

newbeixue的博客 4294

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

CodeSmith的使用

CodeSmith使用 http://bear-study-hard.cnblogs.com/category/43725.html CodeSmith实用技巧系列: http://terrylee.cnblogs.com/archive/2005/12/28/306254.aspx 使用如下方式调试:Debug="False"Debugger.Break(); 转载于:htt...

weixin_30722589的博客 78

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

过TP驱动5(双击调试)

windbg下,ret掉KdDisableDebugger。   然后TP驱动里面会出现死循环,从KdDisableDebugger开始单步跟,nop掉循环判断,   继续单步跟,会发现紧接着一个自写的KdDisableDebugger函数,同样咔嚓掉。

guoyi987的专栏 1643

【读入】#36 A. Extra-terrestrial Intelligence

A. Extra-terrestrial Intelligence time limit per test 2 seconds memory limit per test 64 megabytes input input.txt output output.txt Recently Vasya got interested in fin

CD's Coding 854

代码的写法检查

好东西啊,不管了,先超过在说。 软件中的大多Bug都与各种低级错误有关,而大多低级错误是靠测试测不出来的,更多的需要Code Review来发现问题。 培养好的习惯,不靠任何假设编程,可以先从写好每个函数开始,我想用注释驱动来提醒自己经常Review每个函数。 以下是我拟定的Code Review Comments: /* ### Code Review * ### Revie...

weixin_30652271的博客 109

(OK) cBPM(段错误(吐核))—((EndWorkflowEvent*)evt)->getProcessID()—getenv 返NULL

★★★★★上面的问题——解决了: --------> /opt/cBPM/criteria-lin/src/Criteria/Criteria.WorkflowEngine/events/WorkflowListener.cpp 注释掉两行:(取消注释,会出现上面问题,有待解决)       else if ( evt->getName()

张同光 (Tongguang Zhang):Hello everyone ! 640

现代C++核心难点解析:指针、模板、多线程实战指南

C++作为高性能编程语言的核心在于其内存管理和并发编程能力。指针概念是理解内存布局的基础,通过地址直接操作内存数据,但传统裸指针容易产生内存泄漏和悬空指针问题。现代C++引入智能指针机制,如unique_ptr和shared_ptr,通过RAII技术自动管理资源生命周期,显著提升代码安全性。模板编程则实现了泛型设计,允许编写类型无关的算法和数据结构,STL容器就是典型应用。多线程编程通过std::thread实现并发执行,配合mutex等同步机制解决资源竞争。这些技术在系统编程、游戏引擎等场景中至关重要,本

weixin_30781107的博客 421

芯参谋(92):XTX_存储器件跨RTOS移植速查

本文为XTX SDNAND与SPINOR在FreeRTOS、RT-Thread、AliOSThings、Zephyr四类RTOS上的跨平台移植速查指南。核心结论:SDNAND本质为带控制器的贴片SD卡,均通过各自系统SD/MMC协议栈+FatFs实现,关键在打通SDIO/SPI并挂载文件系统;SPINOR则依赖各系统串行闪存框架(如SFUD、jedec,spi-nor),难点在于型号自动识别。对比显示,RT-Thread与Zephyr因支持自动识别与开箱即用,移植效率最高;FreeRTOS与AliOS需手动

qq520131714的专栏 662

Linux-iostat命令详解

Linux命令学习记录

m0xin的博客 87

线程同步和互斥

生产者和消费者彼此之间不直接通讯,而是通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于⼀个缓冲区,平衡了生产者和消费者的处理能力。<3>当线程A执行完临界区的代码,将1写入到内存mutex中,此时唤醒线程B,线程B执行到exchgb就可以申请到锁了,调度到线程A,线程A就要阻塞等待。结论:若当前线程正在执行临界区的代码被切换走,此时不会还锁,会带走锁,调度到其他线程,会申请不到锁,阻塞等待。

qq_71009995的博客 242

【C++高并发内存池】 2.ThreadCache设计

前面一个设计了一个定长内存池,经过与传统的内存申请方式对比,初步实现了一个可承受频繁申请与释放的高性能的内存池,这是我们首先要看到的一个内存池被设计出来实现的可观效果。从这里开始,我们将一步步的对高并发内存池进行由浅入深的设计,本节我们来设计ThreadCache。threadcache:线程缓存是每个线程独有的,⽤于小于256KB的内存的分配,线程从这里申请内存 不需要加锁,每个线程独享⼀个cache,这也就是这个并发线程池高效的地方。

cyzzzuzm的博客 205

芯参谋(83):AliOS Things_驱动开发指南

本指南针对AliOSThings驱动开发中的核心痛点,系统梳理了从硬件配置到组件交付的全流程。聚焦“初始化顺序”“分级加载”“CSI隔离”“VFS挂载”等关键问题,提供可照搬的八步开发流程、骨架代码与核查清单。通过明确驱动类型选择、组件化管理、板级静态配置(无DTS)及内核态/用户态运行模式,解决“驱动不注册”“open失败”“偶发死机”等典型难题。配套模板与实战案例,确保驱动可复现、可维护、可裁剪,适用于V3.x弹性微内核平台,助力开发者高效完成稳定可靠的外设驱动开发。

qq520131714的专栏 471

iOS 推送通知怎么实现,从 APNs p8 密钥到 iOS 真机收到第一条推送

iOS 推送通知要跑通,核心是 App ID 开通 Push Notifications 并重新生成描述文件、签名带上 aps-environment、再用 APNs 的 .p8 密钥签 JWT 把推送发到设备令牌。这篇用 KXBuild 按五步做:开能力、加 entitlements、代码里请求权限拿设备令牌、建 .p8 认证密钥、用一段 Node 脚本或 curl 走 HTTP/2 发测试推送,让 iPhone 弹出第一条通知。附拿不到令牌、APNs 报错码、TestFlight 收不到的排查。

2501_91591841的博客 215
上一篇: NSString *到NSString *const的区别
下一篇: Memory Management Overview Page
any2mobile
博客等级 码龄17年 36粉丝 109原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值