“VS ERROR:const.char 类型形参与LPWSTR 类型的实参不兼容 ”的解决办法

本文介绍了解决VS2013中由于默认使用Unicode字符集而导致的LPWSTR类型与string类型不匹配的问题。提供了两种解决方案:一是直接在字符串前加L前缀;二是更改项目设置为使用多字节字符集,并安装MultibyteMFCLibrary。

首先错误的原因是因为VS2013默认使用Unicode字符集,所以对于string的字宽度不一样,导致LPWSTR类型不能直接定义string类型的变量。


第一个最直接也是最笨的解决办法就是在定义LPCWSTR类型的字符串前加上L,直接定义还是会报错。

LPCWSTR music = L"C:\\Users\\Admin\\Desktop\\Tetris.wav";

sndPlaySpund(music,SND_ASYNC);

不过第一种解决办法是“治标不治本”的方法,下面给出一个“一劳永逸”的解决方法

在VS-项目-属性-配置属性下,在项目默认值-字符集里将“使用Unicode字符集改为“使用多字节字符集”


点击确定,这个时候按说编译是不会出现问题了,不过有些VS在修改字符集后还会报另一个错误:“error msb8031”,这是因为你的VS可能不支持多字节字符集编码方式,

解决办法也很简单,在错误提示给的网址里下载一个Multibyte MFC Library并安装,再编译应该就不会有问题了。


#include "stdafx.h" #include <windows.h> BOOL SetBreakPoint(PVOID pFuncAddr); BOOL ClearBreakPoint(PVOID pFuncAddr); BOOL InstallVEHHook(PVECTORED_EXCEPTION_HANDLER Handler); VOID UnInstallVEHHook(); typedef int (WINAPI* PFN_MessageBox)( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box ); int WINAPI My_MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box ); LONG WINAPI VectoredHandler1(struct _EXCEPTION_POINTERS* ExceptionInfo); LONG WINAPI VectoredHandler2(struct _EXCEPTION_POINTERS* ExceptionInfo); LONG WINAPI VectoredHandler3(struct _EXCEPTION_POINTERS* ExceptionInfo); VOID ShowMsgBox(LPCTSTR lpMsg); ULONG_PTR InitTrampolineFun(); PFN_MessageBox g_OriginalMessageBoxA; PVOID g_AddrofMessageBoxA = 0; PVOID g_hVector; BYTE g_OldCode[16] = { 0 }; int main(int argc, char* argv[]) { HMODULE hUser32 = LoadLibrary("user32.dll"); g_AddrofMessageBoxA = (PVOID)GetProcAddress(hUser32, "MessageBoxA"); printf("Address of MessageBoxA = 0x%p\n", g_AddrofMessageBoxA); g_OriginalMessageBoxA = (PFN_MessageBox)InitTrampolineFun(); //跳过开头的Hook printf("Addr of VectoredHandler1 = 0x%p\n", VectoredHandler1); printf("Addr of VectoredHandler2 = 0x%p\n", VectoredHandler2); printf("Addr of VectoredHandler3 = 0x%p\n", VectoredHandler3); //选择安装一个进行测试 InstallVEHHook(VectoredHandler1); //设置断点 SetBreakPoint(g_AddrofMessageBoxA); //call ShowMsgBox("VEH Hook Test."); printf("All Finished!\n"); ClearBreakPoint(g_AddrofMessageBoxA); UnInstallVEHHook(); ShowMsgBox("Hook Cleared"); return 0; } VOID ShowMsgBox(LPCTSTR lpMsg) { MessageBoxA(NULL, lpMsg, "Test", MB_OK); } ULONG_PTR InitTrampolineFun() { ULONG_PTR uResult = 0; PBYTE pFun = NULL; #ifdef _WIN64 //x64需要申请shellcode /* USER32!MessageBoxA: 00000000`779412b8 4883ec38 sub rsp,38h 00000000`779412bc 4533db xor r11d,r11d 00000000`779412bf 44391d760e0200 cmp dword ptr [USER32!gapfnScSendMessage+0x927c (00000000`7796213c)],r11d */ pFun = (PBYTE)VirtualAlloc(NULL, 128, MEM_COMMIT, PAGE_EXECUTE_READWRITE); uResult = (ULONG_PTR)pFun; memset(pFun, 0, 128); memcpy(pFun, (PVOID)g_AddrofMessageBoxA, 4); //拷贝第一条指令,4字节,推荐使用反汇编引擎来实际计算 pFun += 4; //下一条指令构造为jmp [xxxxxx] pFun[0] = 0xFF; pFun[1] = 0x25; *(ULONG_PTR*)(pFun + 6) = (ULONG_PTR)g_AddrofMessageBoxA + 4; //跳回到原函数加4的地方 #else //x86,第一条指令是mov edi,edi,直接跳过即可 uResult = (ULONG_PTR)g_AddrofMessageBoxA + 2; #endif return uResult; } //处理方式,修改参数并返回原函数继续执行 LONG WINAPI VectoredHandler1( struct _EXCEPTION_POINTERS* ExceptionInfo ) { char* szNewMsg = "[VectoredHandler1] Hacked by pediy.com"; LONG lResult = EXCEPTION_CONTINUE_SEARCH; PEXCEPTION_RECORD pExceptionRecord; PCONTEXT pContextRecord; int ret = 0; pExceptionRecord = ExceptionInfo->ExceptionRecord; pContextRecord = ExceptionInfo->ContextRecord; ULONG_PTR* uESP = 0; printf("Exception Address = %p\n", pExceptionRecord->ExceptionAddress); if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT && pExceptionRecord->ExceptionAddress == g_AddrofMessageBoxA) { #ifdef _WIN64 //x64上前四个参数依次为RCX,RDX,R8,R9 //修改第二个参数,即LpMsg printf("lpText = 0x%p %s\n", pContextRecord->Rdx, (char*)pContextRecord->Rdx); pContextRecord->Rdx = (ULONG_PTR)szNewMsg; pContextRecord->Rip = (ULONG_PTR)g_OriginalMessageBoxA; //跳到Trampoline继续执行 #else /* 0012FF70 0040105A /CALL 到 MessageBoxA 来自 VEHHook.00401054 0012FF74 00000000 |hOwner = NULL 0012FF78 00407030 |Text = "VEH Hook" 0012FF7C 0040703C |Title = "Test" 0012FF80 00000000 \Style = MB_OK|MB_APPLMODAL 0012FF84 00401225 返回到 VEHHook.<ModuleEntryPoint>+0B4 来自 VEHHook.00401000 */ printf("ESP = 0x%p\n", pContextRecord->Esp); uESP = (ULONG_PTR*)pContextRecord->Esp; //取中断时的ESP uESP[2] = (ULONG_PTR)szNewMsg; //修改栈中的参数 pContextRecord->Eip = (ULONG_PTR)g_OriginalMessageBoxA; //跳过函数开头 #endif lResult = EXCEPTION_CONTINUE_EXECUTION; } return lResult; } //处理方式:直接调用原函数并替原函数返回 LONG WINAPI VectoredHandler2( struct _EXCEPTION_POINTERS* ExceptionInfo ) { char* szNewMsg = "[VectoredHandler2] Hacked by pediy.com"; LONG lResult = EXCEPTION_CONTINUE_SEARCH; PEXCEPTION_RECORD pExceptionRecord; PCONTEXT pContextRecord; int ret = 0; pExceptionRecord = ExceptionInfo->ExceptionRecord; pContextRecord = ExceptionInfo->ContextRecord; ULONG_PTR* uESP = 0; if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT && pExceptionRecord->ExceptionAddress == g_AddrofMessageBoxA) { #ifdef _WIN64 //x64上前四个参数依次为RCX,RDX,R8,R9 printf("RSP = 0x%p\n", pContextRecord->Rsp); uESP = (ULONG_PTR*)pContextRecord->Rsp; printf("Return Address = 0x%p\n", uESP[0]); ret = g_OriginalMessageBoxA((HWND)pContextRecord->Rcx, szNewMsg, (LPCTSTR)pContextRecord->R8, (int)pContextRecord->R9); printf("ret = %d\n", ret); //修正RSP pContextRecord->Rsp += sizeof(ULONG_PTR);//参数在寄存器中,栈中无参数,仅需跳过返回地址 //直接返回到调用者处 pContextRecord->Rip = uESP[0];//设置EIP为返回地址 #else /* 0012FF70 0040105A /CALL 到 MessageBoxA 来自 VEHHook.00401054 0012FF74 00000000 |hOwner = NULL 0012FF78 00407030 |Text = "VEH Hook" 0012FF7C 0040703C |Title = "Test" 0012FF80 00000000 \Style = MB_OK|MB_APPLMODAL 0012FF84 00401225 返回到 VEHHook.<ModuleEntryPoint>+0B4 来自 VEHHook.00401000 */ printf("ESP = 0x%p\n", pContextRecord->Esp); uESP = (ULONG_PTR*)pContextRecord->Esp; ret = g_OriginalMessageBoxA((HWND)uESP[1], szNewMsg, (LPCTSTR)uESP[3], (int)uESP[4]); printf("ret = %d\n", ret); //直接返回到调用者处 pContextRecord->Eip = uESP[0];//设置EIP为返回地址 pContextRecord->Esp += (4 + 1) * sizeof(ULONG_PTR); //4为参数个数,1为返回地址 #endif lResult = EXCEPTION_CONTINUE_EXECUTION; } return lResult; } //处理方式:直接返回,相当于过滤掉 LONG WINAPI VectoredHandler3( struct _EXCEPTION_POINTERS* ExceptionInfo ) { LONG lResult = EXCEPTION_CONTINUE_SEARCH; PEXCEPTION_RECORD pExceptionRecord = ExceptionInfo->ExceptionRecord; PCONTEXT pContextRecord = ExceptionInfo->ContextRecord; ULONG_PTR* uESP = 0; if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT && pExceptionRecord->ExceptionAddress == g_AddrofMessageBoxA) { /* 0012FF70 0040105A /CALL 到 MessageBoxA 来自 VEHHook.00401054 0012FF74 00000000 |hOwner = NULL 0012FF78 00407030 |Text = "VEH Hook" 0012FF7C 0040703C |Title = "Test" 0012FF80 00000000 \Style = MB_OK|MB_APPLMODAL 0012FF84 00401225 返回到 VEHHook.<ModuleEntryPoint>+0B4 来自 VEHHook.00401000 */ //直接返回到调用者处 #ifdef _WIN64 printf("RSP = 0x%p\n", pContextRecord->Rsp); uESP = (ULONG_PTR*)pContextRecord->Rsp; pContextRecord->Rip = uESP[0];//设置EIP为返回地址 pContextRecord->Rsp += sizeof(ULONG_PTR); //将压入栈内的参数和返回地址清理掉,4为参数个数,1为返回地址 #else printf("ESP = 0x%X\n", pContextRecord->Esp); uESP = (ULONG_PTR*)pContextRecord->Esp; pContextRecord->Eip = uESP[0];//设置EIP为返回地址 pContextRecord->Esp += (4 + 1) * sizeof(ULONG_PTR); //将压入栈内的参数和返回地址清理掉,4为参数个数,1为返回地址 #endif lResult = EXCEPTION_CONTINUE_EXECUTION; } return lResult; } BOOL InstallVEHHook(PVECTORED_EXCEPTION_HANDLER Handler) { printf("Current Handler Address = 0x%p\n", Handler); g_hVector = AddVectoredExceptionHandler(1, Handler); return g_hVector != NULL; } VOID UnInstallVEHHook() { RemoveVectoredExceptionHandler(g_hVector); } /* 0:000> u user32!messageboxA USER32!MessageBoxA: 77d507ea 8bff mov edi,edi 77d507ec 55 push ebp 77d507ed 8bec mov ebp,esp */ BOOL SetBreakPoint(PVOID pFuncAddr) { DWORD dwCnt = 0; BYTE* pTarget = (BYTE*)pFuncAddr; g_OldCode[0] = *pTarget; printf("Original Fun Head Code = 0x%02X\n", g_OldCode[0]); //修改内存页的属性 DWORD dwOLD; MEMORY_BASIC_INFORMATION mbi; VirtualQuery(pTarget, &mbi, sizeof(mbi)); VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOLD); //写入int3 *pTarget = 0xCC; //恢复内存页的属性 VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOLD, 0); return TRUE; } BOOL ClearBreakPoint(PVOID pFuncAddr) { BYTE* pTarget = (BYTE*)pFuncAddr; //修改内存页的属性 DWORD dwOLD; MEMORY_BASIC_INFORMATION mbi; VirtualQuery(pTarget, &mbi, sizeof(mbi)); VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOLD); *pTarget = g_OldCode[0]; //恢复内存页的属性 VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOLD, 0); return TRUE; } int WINAPI My_MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box ) { char newMsg[400]; char newCation[] = "标题被我改了!"; int result; if (lpText) { ZeroMemory(newMsg, 400); lstrcpy(newMsg, lpText); lstrcat(newMsg, "\n\tMessage Box hacked by pediy.com"); } printf("有人调用MessageBox...\n"); result = g_OriginalMessageBoxA(hWnd, newMsg, newCation, uType); return result; }严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息 错误(活动) E0020 未定义标识符 "printf" veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 41 错误(活动) E0020 未定义标识符 "printf" veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 116 错误(活动) E0020 未定义标识符 "printf" veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 166 错误(活动) E0020 未定义标识符 "printf" veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 225 错误(活动) E0020 未定义标识符 "printf" veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 243 错误(活动) E0020 未定义标识符 "printf" veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 267 错误(活动) E0020 未定义标识符 "printf" veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 314 错误 C1083 无法打开包括文件: “stdafx.h”: No such file or directory veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 3 错误(活动) E1696 无法打开 源 文件 "stdafx.h" veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 3 错误(活动) E0167 "LPCTSTR" (aka "const WCHAR *") 类型实参与 "LPCSTR" (aka "const CHAR *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 68 错误(活动) E0167 "const char *" 类型实参与 "LPCWSTR" (aka "const WCHAR *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 39 错误(活动) E0167 "const char *" 类型实参与 "LPCWSTR" (aka "const WCHAR *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 312 错误(活动) E0167 "const char *" 类型实参与 "LPCTSTR" (aka "const WCHAR *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 55 错误(活动) E0167 "const char *" 类型实参与 "LPCTSTR" (aka "const WCHAR *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 62 错误(活动) E0144 "const char *" 类型的值不能用于初始化 "char *" 类型的实体 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 108 错误(活动) E0144 "const char *" 类型的值不能用于初始化 "char *" 类型的实体 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 152 错误(活动) E0167 "char *" 类型实参与 "LPWSTR" (aka "wchar_t *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 311 错误(活动) E0167 "char *" 类型实参与 "LPWSTR" (aka "wchar_t *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 312 错误(活动) E0167 "char *" 类型实参与 "LPCTSTR" (aka "const WCHAR *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 169 错误(活动) E0167 "char *" 类型实参与 "LPCTSTR" (aka "const WCHAR *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 315 错误(活动) E0167 "char *" 类型实参与 "LPCTSTR" (aka "const WCHAR *") 类型不兼容 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 315
最新发布
07-25
<think>我们正在解决VisualStudio2010中C++类型不匹配的问题:const char*类型实参char*类型不兼容。根据引用[1]和引用[2],我们可以总结出以下几种解决方法:方法1:使用const_cast进行强制类型转换(适用于临时转换字符串字面值)char* str= const_cast<char*>("123");方法2:使用字符数组作为中转charch1[] ="Helloworld";char* text= ch1;方法3:在定义参或成员变量时,将char*改为const char*(如果不会修改字符串内容,推荐使用)例如,在类定义中:const char*name;//而不是 char*name;方法4:通过项目属性设置(不推荐,因为会降低代码安全性)在项目属性 ->配置属性-> C/C++->语言 ->符合模式,设置为“否”(/Zc:strictStrings-)注意:这种方法在VS2010中可能不可用,因为/Zc:strictStrings是VS2013及以后版本引入的。根据问题描述,用户使用的是VS2010,所以方法4可能不适用。因此,我们主要推荐前三种方法。下面详细说明:1.使用const_cast:这种方法直接对字符串字面值进行转换,但要注意:字符串字面值存储在只读内存区域,通过char*指针修改它们会导致未定义行为。因此,只有在确定不会修改字符串内容时才使用。示例:voidfunc(char*str){ ...}func(const_cast<char*>("Hello"));//调用2.使用字符数组:将字符串字面值赋值给一个字符数组(数组大小足够),然后将该数组赋值给char*指针。因为数组是在栈上分配的,内容可修改(但这里我们初始化的字符串是常量,所以实际上修改也是不安全的,但类型匹配了)。示例:charbuffer[]= "Hello";func(buffer);//因为buffer是char[]类型,可以退化为char*3.修改函数参或成员变量为constchar*:如果函数内部不需要修改字符串内容,那么将类型改为const char*是最安全的方式。示例:voidfunc(constchar*str){ ...}//修改函数声明func("Hello");//直接传递字符串字面值或者在类中:class MyClass {public:const char* name;//而不是char* name};注意:在C++中,字符串字面值(如"Hello")的类型constchar[N],在C++03中退化为constchar*,因此不能直接赋值给char*。在VS2010中,默认设置下不允许将字符串字面值赋给char*(这是符合标准的)。因此,根据具体情况选择方法:-如果函数或成员变量不需要修改字符串,则使用const char*(方法3)是最佳选择,安全且符合标准。-如果必须使用char*(例如,某些旧接口无法修改),并且确定不会修改字符串,则可以使用const_cast(方法1)或字符数组(方法2)。特别提醒:避免使用const_cast去修改真正的常量,否则会导致未定义行为。下面给出一个示例代码,展示如何修改:问题重现:以下代码在VS2010中会报错const char*类型实参char*类型不兼容voidMyFunction(char* str) {//使用str}intmain(){MyFunction("Hello");//错误return0;}解决方法1(修改函数参):void MyFunction(constchar*str){//修改参为const char*//注意:函数内部不能修改str指向的内容}解决方法2(使用const_cast):intmain(){MyFunction(const_cast<char*>("Hello"));//强制转换return0;}解决方法3(使用字符数组):intmain(){char arr[] ="Hello";MyFunction(arr);//arr是char数组,可以转换为char*return0;}根据引用[2]中的例子,如果是在类成员变量上出现此问题,则修改成员变量类型constchar*:class Student{public://修改前:char*name;const char*name;//修改后//...其他成员};然后,在赋值时可以直接使用字符串字面值:Student*pStu =new Student;pStu->name ="小明";//现在合法了总结:推荐优先使用方法3(修改const char*)以符合类型安全。如果无法修改函数或成员变量(例如,使用的是第三方库),则考虑使用const_cast或字符数组。注意:在C++11及以后的标准中,字符串字面值被规定为具有常量性,因此上述问题同样存在,解决方法相同。相关问题:1.为什么在C++中字符串字面值不能直接赋值给char*指针?2.使用const_cast转换字符串字面值有什么风险?3.在C++中,如何安全地处理字符串字面值和char*之间的转换?</think>### VS2010 C++ `const char*` 实参与 `char*` 不兼容的解决方法 在 Visual Studio 2010 中,当字符串字面值(如 `"Hello"`)传递给 `char*` 参时,会出现类型不兼容错误。这是因为 C++ 标准规定**字符串字面值具有常量性**(类型为 `const char[N]`),不能直接赋值给非常量指针。以下是 4 种解决方案: --- #### 方法 1:修改类型为 `const char*`(推荐) 在函数声明或类成员定义中直接使用 `const char*`: ```cpp // 函数修改 void printString(const char* str) { // ✅ 添加 const std::cout << str; } // 类成员修改 class Employee { public: const char* name; // ✅ 添加 const }; ``` **原理**:匹配字符串字面值的常量特性,符合类型安全要求[^2]。 --- #### 方法 2:使用 `const_cast` 强制转换 在调用处显式移除常量性(需确保不修改字符串): ```cpp void unsafeFunc(char* str); // 第三方库函数,无法修改声明 int main() { unsafeFunc(const_cast<char*>("Temp")); // ⚠️ 强制转换 } ``` **风险**:若函数尝试修改字符串,会导致未定义行为(崩溃)[^1]。 --- #### 方法 3:字符数组中转 通过可修改的字符数组传递: ```cpp char buffer[] = "Hello"; // ✅ 栈上分配可修改数组 unsafeFunc(buffer); // 类型匹配: char[] → char* ``` **优势**:安全且无转换开销,数组内容可修改。 --- #### 方法 4:禁用严格字符串检查(不推荐) 在项目属性中关闭标准兼容性(VS2010 可能不支持): 1. 右键项目 → **属性** 2. **C/C++ → 语言** 3. 设置 `const char*` 的严格类型检查为 **否**(`/Zc:strictStrings-`) **注意**:此操作降低代码安全性,且 VS2010 默认无此选项[^1]。 --- ### 最佳实践总结 | 方案 | 安全性 | 适用场景 | 代码改动量 | |------|--------|----------|------------| | 修改为 `const char*` | ★★★★★ | 可修改源码时 | 低 | | 字符数组中转 | ★★★★☆ | 需局部修改字符串时 | 中 | | `const_cast` | ★★☆☆☆ | 调用不可修改的旧接口 | 低 | | 禁用严格检查 | ★☆☆☆☆ | 临时解决方案 | 无 | > **关键原则**:优先保持类型安全。若函数不修改字符串,务必使用 `const char*`;若需修改,则使用字符数组[^2][^3]。 --- ### 相关问题 1. 为什么 C++ 中字符串字面值默认是 `const char*` 类型? 2. 使用 `const_cast` 转换字符串字面值有哪些潜在风险? 3. 在 C++11 及更高版本中,如何处理字符串字面值与 `char*` 的兼容性问题? 4. 如何设计安全的字符串传递接口以避免此类类型错误? [^1]: IDE 转换与属性设置方法 [^2]: 类成员添加 `const` 修饰的解决方案 [^3]: 实际应用场景中的类型兼容问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值