• evc vc字符串转换处理


    1.头文件中要定义宏;

    #define  UNICODE 
    #define  _UNICODE 
    ////////////////////
    
    char   buf[128];  
    memset(buf, 0, 128);  
    strcpy(buf, "你好");  
    WCHAR  pCName[128];  
    memset(pCName, 0,1 28);  
    MultiByteToWideChar(CP_THREAD_ACP, MB_USEGLYPHCHARS, buf, strlen(buf), pCName, 128); 

    至于WCHAR   转换到CHAR,则用 
    WideCharToMultiByte

    //////////////////////////

    2.char转换成wchar

    const  char  *pFilePathName  =  "c:\\aa.dll"; 
    int  nLen  =  strlen(pFilePathName)  +  1; 
    int  nwLen  =  MultiByteToWideChar(CP_ACP,  0,  pFilePathName, nLen,  NULL,  0); 
    
    TCHAR  lpszFile[256]; 
    MultiByteToWideChar(CP_ACP,  0,  pFilePathName,  nLen,  lpszFile, nwLen); 
    

    3.wchar转换成char

    char  *pFilePathName; 
    TCHAR  lpszFile[256]; 
    _tcscpy(lpszFile,  _T("c:\\aa.dll")); 
    int  nLen  =  wcslen(wstr)+1; 
    WideCharToMultiByte(CP_ACP,  0,  lpszFile,  nLen,  pFilePathName, 2*nLen,  NULL,  NULL);
     

    char*和CString转换
    CString 是一种很特殊的 C++ 对象,它里面包含了三个值:一个指向某个数据缓冲区的指针、一个是该缓冲中有效的字符记数(它是不可存取的,是位于
    CString 地址之下的一个隐藏区域)以及一个缓冲区长度。
    有效字符数的大小可以是从0到该缓冲最大长度值减1之间的任何数(因为字符串结尾有一个NULL字符)。字符记数和缓冲区长度被巧妙隐藏。

    (1) char*转换成CString
      若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:

          char chArray[] = "Char  test";
          TCHAR * p = _T("Char  test");( 或?LPTSTR p = _T("Char  test");)
          CString theString = chArray;
          theString.Format(_T("%s"), chArray);
          theString = p;

    (2) CString转换成char*

      若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:

      方法一,使用强制转换。例如:

           CString theString( (_T("Char test "));
           LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;

      方法二,使用strcpy。例如:

           CString theString( (_T("Char test "));
           LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
           _tcscpy(lpsz, theString);

           需要说明的是,strcpy(或可移值的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char*(ANSI),系统编译器将会自动对其进行转换。

      方法三,使用CString::GetBuffer。
               如果你需要修改 CString 中的内容,它有一个特殊的方法可以使用,那就是 GetBuffer,它的作用是返回一个可写的缓冲指针。
               如果你只是打算修改字符或者截短字符串,例如:

      CString s(_T("Char test "));
      LPTSTR p = s.GetBuffer();
      LPTSTR dot = strchr(p, ''.'');
    

               // 在这里添加使用p的代码

      if(p != NULL)
      *p = _T('\0');
      s.ReleaseBuffer(); // 使用完后及时释放,以便能使用其它的CString成员函数
    在 GetBuffer 和 ReleaseBuffer 之间这个范围,一定不能使用你要操作的这个缓冲的 CString 对象的任何方法。因为ReleaseBuffer 被调用之前,该 CString 对象的完整性得不到保障。
     

    CString ,BSTR ,LPCTSTR之间关系和区别

    CString是一个动态TCHAR数组,BSTR是一种专有格式的字符串(需要用系统提供的函数来操纵,LPCTSTR只是一个常量的TCHAR指针。

    CString 是一个完全独立的类,动态的TCHAR数组,封装了 + 等操作符和字符串操作方法。

    typedef OLECHAR FAR* BSTR;
    typedef const char * LPCTSTR;

    vc++中各种字符串的表示法
    首先char*是指向ANSI字符数组的指针,其中每个字符占据8位(有效数据是除掉最高位的其他7位),这里保持了与传统的C,C++的兼容。
    LP的含义是长指针(long pointer)。LPSTR是一个指向以‘\0’结尾的ANSI字符数组的指针,与char*可以互换使用,在win32中较多地使用LPSTR。
    而LPCSTR中增加的‘C’的含义是“CONSTANT”(常量),表明这种数据类型的实例不能被使用它的API函数改变,除此之外,它与LPSTR是等同的。
    1.LP表示长指针,在win16下有长指针(LP)和短指针(P)的区别,而在win32下是没有区别的,都是32位.所以这里的LP和P是等价的.
    2.C表示const
    3.T是什么东西呢,我们知道TCHAR在采用Unicode方式编译时是wchar_t,在普通时编译成char.


    为了满足程序代码国际化的需要,业界推出了Unicode标准,它提供了一种简单和一致的表达字符串的方法,所有字符中的字节都是16位的值,其数量也可以满足差不多世界上所有书面语言字符的编码需求,开发程序时使用Unicode(类型为wchar_t)是一种被鼓励的做法。
    LPWSTR与LPCWSTR由此产生,它们的含义类似于LPSTR与LPCSTR,只是字符数据是16位的wchar_t而不是char。
    然后为了实现两种编码的通用,提出了TCHAR的定义:
    如果定义_UNICODE,声明如下:
    typedef wchar_t TCHAR;
    如果没有定义_UNICODE,则声明如下:
    typedef char TCHAR;
    LPTSTR和LPCTSTR中的含义就是每个字符是这样的TCHAR。
    CString类中的字符就是被声明为TCHAR类型的,它提供了一个封装好的类供用户方便地使用。

    LPCTSTR:
    #ifdef _UNICODE
    typedef const wchar_t * LPCTSTR;
    #else
    typedef const char * LPCTSTR;
    #endif
    

    VC常用数据类型使用转换详解
    先定义一些常见类型变量借以说明

    int i = 100;
    long l = 2001;
    float f=300.2;
    double d=12345.119;
    char username[]="木瓜";
    char temp[200];
    char *buf;
    CString str;
    _variant_t v1;
    _bstr_t v2;
    

    一、其它数据类型转换为字符串
    短整型(int)
    itoa(i,temp,10);
    //将i转换为字符串放入temp中,最后一个数字表示十进制
    itoa(i,temp,2);  //按二进制方式转换
    长整型(long)
    ltoa(l,temp,10);

    二、从其它包含字符串的变量中获取指向该字符串的指针
    CString变量
    str = "2008北京奥运";
    buf = (LPSTR)(LPCTSTR)str;
    BSTR类型的_variant_t变量
    v1 = (_bstr_t)"程序员";
    buf = _com_util::ConvertBSTRToString((_bstr_t)v1);
    三、字符串转换为其它数据类型
    strcpy(temp,"123");
    短整型(int)
    i = atoi(temp);
    长整型(long)
    l = atol(temp);
    浮点(double)
    d = atof(temp);
    四、其它数据类型转换到CString
    使用CString的成员函数Format来转换,例如:
    整数(int)
    str.Format("%d",i);
    浮点数(float)
    str.Format("%f",i);
    字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值
    str = username;
    五、BSTR、_bstr_t与CComBSTR
    CComBSTR、_bstr_t是对BSTR的封装,BSTR是指向字符串的32位指针。
    char *转换到BSTR可以这样: BSTR
    b=_com_util::ConvertStringToBSTR("数据");
    //使用前需要加上头文件comutil.h
    反之可以使用char *p=_com_util::ConvertBSTRToString(b);

    六、VARIANT 、_variant_t 与 COleVariant
    VARIANT的结构可以参考头文件VC98\Include\OAIDL.H中关于结构体tagVARIANT的定义。
    对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子:

    VARIANT va;
    int a=2001;
    va.vt=VT_I4;  //指?明?整?型?数?据?
    va.lVal=a;  //赋?值?
    

    对于不马上赋值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR*  pvarg);进行初始化,其本质是将vt设置为VT_EMPTY,下表我们列举vt与常用数据的对应关系:
    unsigned char bVal; VT_UI1
    short iVal; VT_I2
    long lVal;  VT_I4
    float fltVal;  VT_R4
    double dblVal;  VT_R8
    VARIANT_BOOL boolVal;  VT_BOOL
    SCODE scode;  VT_ERROR
    CY cyVal;  VT_CY
    DATE date;  VT_DATE
    BSTR bstrVal;  VT_BSTR
    IUnknown FAR* punkVal;  VT_UNKNOWN
    IDispatch FAR* pdispVal;  VT_DISPATCH
    SAFEARRAY FAR* parray;  VT_ARRAY|*
    unsigned char FAR* pbVal;  VT_BYREF|VT_UI1
    short FAR* piVal;  VT_BYREF|VT_I2
    long FAR* plVal;  VT_BYREF|VT_I4
    float FAR* pfltVal;  VT_BYREF|VT_R4
    double FAR* pdblVal; VT_BYREF|VT_R8
    VARIANT_BOOL FAR* pboolVal; VT_BYREF|VT_BOOL
    SCODE FAR* pscode;  VT_BYREF|VT_ERROR
    CY FAR* pcyVal;  VT_BYREF|VT_CY
    DATE FAR* pdate; VT_BYREF|VT_DATE
    BSTR FAR* pbstrVal;  VT_BYREF|VT_BSTR
    IUnknown FAR* FAR* ppunkVal;  VT_BYREF|VT_UNKNOWN
    IDispatch FAR* FAR* ppdispVal;
    VT_BYREF|VT_DISPATCH
    SAFEARRAY FAR* FAR* pparray;  VT_ARRAY|*
    VARIANT FAR* pvarVal;  VT_BYREF|VT_VARIANT
    void FAR* byref;  VT_BYREF


    _variant_t是VARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。
    例如:
    long l=222;
    int i=100;
    _variant_t lVal(l);
    lVal = (long)i;
    COleVariant的使用与_variant_t的方法基本一样,请参考如下例子:
    COleVariant v3 = "字符串", v4 = (long)1999;
    CString str =(BSTR)v3.pbstrVal;
    long i = v4.lVal;

    七、其它
    对消息的处理中我们经常需要将WPARAM或LPARAM等32位数据(DWORD)分解成两个16位数据(WORD),例如:
    对于16位的数据(WORD)我们可以用同样的方法分解成高低两个8位数据(BYTE),例如:
    WORD wValue;
    BYTE loValue = LOBYTE(wValue);  //取低8位
    BYTE hiValue = HIBYTE(wValue);  //取高8位

    如何将CString类型的变量赋给char*类型的变量
    1、GetBuffer函数:
    使用CString::GetBuffer函数。

    char *p;
    CString str="hello";
    p=str.GetBuffer(str.GetLength());
    str.ReleaseBuffer();

    将CString转换成char * 时

    CString str("aaaaaaa");
    strcpy(str.GetBuffer(10),"aa");
    str.ReleaseBuffer();
    当我们需要字符数组时调用GetBuffer(int  n),其中n为我们需要的字符数组的长度.使用完成后一定要马上调用ReleaseBuffer();
    还有很重要的一点就是,在能使用const char *的地方,就不要使用char *
    2、memcpy:
    CString mCS=_T("cxl");
    char mch[20];
    memcpy(mch,mCS,20);
    3、用LPCTSTR强制转换: 尽量不使用
    char *ch;
    CString str;
    ch=(LPSTR)(LPCTSTR)str;
    CString str = "good";
    char *tmp;
    sprintf(tmp,"%s",(LPTSTR)(LPCTSTR)str);
    4、
    CString Msg;
    Msg=Msg+"abc";
    LPTSTR lpsz;
    lpsz = new TCHAR[Msg.GetLength()+1];
    _tcscpy(lpsz, Msg);
    char * psz;
    strcpy(psz,lpsz);

    CString类向const char *转换
    char a[100];
    CString str("aaaaaa");
    strncpy(a,(LPCTSTR)str,sizeof(a));
    或者如下:
    strncpy(a,str,sizeof(a));
    以上两种用法都是正确地. 因为strncpy的第二个参数类型为const char *.所以编译器会自动将CString类转换成const char *.
    CString转LPCTSTR (const char *)
    CString cStr;
    const char *lpctStr=(LPCTSTR)cStr;
    LPCTSTR转CString
    LPCTSTR lpctStr;
    CString cStr=lpctStr;
    将char*类型的变量赋给CString型的变量
    可以直接赋值,如:
    CString myString = "This is a test";
    也可以利用构造函数,如:
    CString s1("Tom");
    将CString类型的变量赋给char []类型(字符串)的变量
    1、sprintf()函数

    CString str = "good";
    char tmp[200] ;
    sprintf(tmp, "%s",(LPCSTR)str);
    (LPCSTR)str这种强制转换相当于(LPTSTR)(LPCTSTR)str
    CString类的变量需要转换为(char*)的时,使用(LPTSTR)(LPCTSTR)str
    然而,LPCTSTR是const char *,也就是说,得到的字符串是不可写的!将其强制转换成LPTSTR去掉const,是极为危险的!
    一不留神就会完蛋!要得到char *,应该用GetBuffer()或GetBufferSetLength(),用完后再调用ReleaseBuffer()。
    2、strcpy()函数
    CString str;
    char c[256];
    strcpy(c, str);
    char mychar[1024];
    CString source="Hello";
    strcpy((char*)&mychar,(LPCTSTR)source);

    关于CString的使用
    1、指定 CString 形参
    对于大多数需要字符串参数的函数,最好将函数原型中的形参指定为一个指向字符 (LPCTSTR)
    而非 CString 的 const 指针。
    当将形参指定为指向字符的 const 指针时,可将指针传递到 TCHAR 数组(如字符串 ["hi
    there"])或传递到 CString 对象。
    CString 对象将自动转换成 LPCTSTR。任何能够使用 LPCTSTR 的地方也能够使用
    CString 对象。
    2、如果某个形参将不会被修改,则也将该参数指定为常数字符串引用(即 const CString&)。

    如果函数要修改该字符串,则删除 const 修饰符。如果需要默认为空值,则将其初始化为空字符串 [""],如下所示:
    void AddCustomer( const CString& name, const
    CString& address, const CString& comment = "" );
    3、对于大多数函数结果,按值返回 CString 对象即可。

    串的基本运算
    对于串的基本运算,很多高级语言均提供了相应的运算符或标准的库函数来实现。
    为叙述方便,先定义几个相关的变量:
    char s1[20]="dir/bin/appl", s2[20]="file.asm",s3[30],*p;
    int result;


    下面以C语言中串运算介绍串的基本运算
    1、求串长
    int strlen(char *s);  //求串s的长度
    【例】printf("%d",strlen(s1));  //输出s1的串长12
    2、串复制
    char *strcpy(char
    *to,*from);//将from串复制到to串中,并返回to开始处指针
    【例】strcpy(s3,s1);  //s3="dir/bin/appl",s1串不变

    3、联接
    char *strcat(char *to,char
    *from);//将from串复制到to串的末尾,
    //并返回to串开始处的指针
    【例】strcat(s3,"/");  //s3="dir/bin/appl/"
    strcat(s3,s2);
    //s3="dir/bin/appl/file.asm"
    4、串比较
    int strcmp(char *s1,char *s2);//比较s1和s2的大小,
    //当s1<s2、s1>s2和s1=s2时,分别返回小于0、大于0和等于0的值
    【例】result=strcmp("baker","Baker");
    //result>0
    result=strcmp("12","12");
    //result=0
    result=strcmp("Joe","joseph")
    //result<0
    5、字符定位
    char *strchr(char *s,char c);//找c在字符串s中第一次出现的位置,
    //若找到,则返回该位置,否则返回NULL
    【例】p=strchr(s2,'.');  //p指向"file"之后的位置
       if(p) strcpy(p,".cpp");  //s2="file.cpp"
    注意:
     ①上述操作是最基本的,其中后4个操作还有变种形式:strncpy,strncath和strnchr。
     ②其它的串操作见C的<string.h>。在不同的高级语言中,对串运算的种类及符号都不尽相同
     ③其余的串操作一般可由这些基本操作组合而成
    【例】求子串的操作可如下实现:
    void substr(char *sub,char *s,int pos,int
    len){
    //s和sub是字符数组,用sub返回串s的第pos个字符起长度为len的子串
    //其中0<=pos<=strlen(s)-1,且数组sub至少可容纳len+1个字符。
    if (pos<0||pos>strlen(s)-1||len<0)
         Error("parameter error!");
    strncpy(sub,&s[pos],len);
    //从s[pos]起复制至多len个字符到sub

    CString 型转化成 int 型

      把 CString 类型的数据转化成整数类型最简单的方法就是使用标准的字符串到整数转换例程。
      虽然通常你怀疑使用_atoi()函数是一个好的选择,它也很少会是一个正确的选择。如果你准备使用 Unicode  字符,你应该用_ttoi(),它在 ANSI 编码系统中被编译成_atoi(),而在 Unicode编码系统中编译成_wtoi()。你也可以考虑使用_tcstoul()或者_tcstol(),它们都能把字符串转化成任意进制的长整数(如二进制、八进制、十进制或十六进制),不同点在于前者转化后的数据是无符号的(unsigned),而后者相反。看下面的例子
    CString hex = _T("FAB");

    CString decimal = _T("4011");

    ASSERT(_tcstoul(hex, 0, 16) == _ttoi(decimal));

    CString格式化字符串

    与其用 sprintf() 函数或 wsprintf() 函数来格式化一个字符串,还不如用 CString对象的Format()方法:
    CString s;s.Format(_T("The total is %d"), total);  

    用这种方法的好处是你不用担心用来存放格式化后数据的缓冲区是否足够大,这些工作由CString类替你完成。格式化是一种把其它不是字符串类型的数据转化为CString类型的最常用技巧,比如,把一个整数转化成CString类型,可用如下方法:
    CString s;s.Format(_T("%d"), total); 

    在EVC下,我将CString转为Char  *的时候可以这样写

    #include  <atlconv.h>
    ... USES_CONVERSION;
    CString  str="Cstring";
    char  *p;
    p=(char*)W2A((LPCTSTR)str); 

    或者这样写

    CString strDemo;

    char AnsiString[MAX_PATH] = { 0 };
    wcstombs(AnsiString, (LPTSTR)(LPCTSTR)strDemo, strDemo.GetLength());

    或者这样写

    char* = (LPSTR)(LPCTSTR)CString;
    const char* = (LPCSTR)(LPCTSTR)CString;

    或者这样写

    CString strFilePath;
    char FilePath[256];
    memset( FilePath, 0, 256 );
    strFilePath = "hello world";
    WideCharToMultiByte( CP_ACP, 0, strFilePath, -1, FilePath, 256,
    NULL, NULL);
    ...
    或者这样写

    首先获得char缓冲区大小,然后再通过WideCharToMultiByte转换
    CString strConvert;
    char pchBuffer;
    int iSize;
    iSize = WideCharToMultiByte(CP_ACP,0, strFilePath.GetBuffer(0), -1,
    NULL, 0, NULL, NULL);
    pchBuffer = new char[iSize*2 + 1];
    if(pchBuffer != NULL)
    {
          memset(pchBuffer , 0 , (iSize*2 + 1)*sizeof(char));
    }
    WideCharToMultiByte(CP_ACP,0, strFilePath.GetBuffer(0), -1,
    pchBuffer, (iSize*2 + 1), NULL, NULL);

    浅谈EVC中文字符串操作
    EVC在某种意义上说,相当于VC的一个子集。因为大多EVC有的功能,VC也具备,而VC有的功能,EVC则不一定拥有。在VC中,操作字符串很方便,因为WINDOWS的字处理能力实在是很强大,它支持多种字符集。我们随便使用一个CString str=“你好”,就要以输入我们想要的中文字符串。在EVC中这种情况有所改变,因为WINCE的字处理能力不够强大,它在处理汉字里统一将它示为UNICODE编码,所以我们在EVC中片理中文字符串时需要用到UNICODE编码。下面结合WINDOWS 下VC字符串的处理,对比一下EVC中文字符串的片理方法。

    一、中文字符串定义
    1、在VC中我们如果定义一个中文字符串,可以使用CString str=“你好”或LPCTSTR  str=“你好”。
    2、在EVC中我们如果想定义一个中文字符串,可以使用如下方法:CString str=_T(“你好”)或者LPCTSTR  str=“你好”,这里LPCTSTR在EVC里就是表示UNICODE字符串。值得注意的是_T()宏中,括号中只能填写常量,不能填定变量。
    二、字符串操作
    1、在VC中我们想拷贝字符串,可以作如下操作:
    char s[20];
    CString str=“你好”;
    strcpy(s,str);
    在EVC中则不能这样做,首先定义中文数组应该用双字节指针wchar_t,而拷贝函数也不能用strcpy,而应该用:wchar_t * wcscpy(wchar_t * wDest,wchar_t wSource);函数,操作如下:
    wchar_t s[20];
    CString str=“你好”;
    wcscpy(s,(LPCTSTR)str); //前面没有转成UNICODE编码,所以这里需要强制转换
    2、在VC中我们想在一个字符串中查找某个子串,只需要作下面的操作:
    CString str=“你是一个好学生”;
    str.Find(“学生”);
    在EVC中不能这样做,因为中文字符串为UNICODE编码,我们必需在查找函数的参数里作如下修改:
    str.Find(_T(“学生”));

    以上是我在用EVC写应用程序时操作中文字符串的一些积累,以文记之,以备不时之需。

    单宽字节互换的程序,估计以后还用得着。

    void MyWideCharToMultiByte(WCHAR* wchars,CHAR* schars,int scharsLen)
    {
        memset(schars,0,scharsLen);
        CString m_snd = wchars;
        int len = m_snd.GetLength();
        CString tmpstr(m_snd); //复制要发送的字符串
        int multibytelen=WideCharToMultiByte( //计算从Unicode转换到Ansi后需要的字节数
            CP_ACP, //根据ANSI code page转换
            WC_COMPOSITECHECK | WC_DEFAULTCHAR, //转换出错用缺省字符代替
            (LPCWSTR)tmpstr.GetBuffer(len), //要转换的字符串地址
            len, //要转换的个数
            0, //转换后字符串放置的地址
            0, //最多转换字符的个数,为0表示返回转换Unicode后需要多少个字节
            0, //缺省的字符:"\0"
            0 //缺省的设置
            );
        WideCharToMultiByte( //转换Unicode到Ansi
            CP_ACP,
            WC_COMPOSITECHECK | WC_DEFAULTCHAR,
            (LPCWSTR)tmpstr.GetBuffer(len),
            len,
            (char *)schars, //转换到缓冲区中
            scharsLen, //最多个字节
            0,
            0
            );
    }
    //程序接收到的字符串最后保存到CString tmpstr中.
    //接收函数片断
    void MyMultiByteToWideChar(char* schars,CString &wstr)
    {
        // TODO: Add your specialized code here and/or call the base class
        //  char * p = "abcdefg我是谁hijk";
        int widecharlen=MultiByteToWideChar( //计算从Ansi转换到Unicode后需要的字节数
            CP_ACP,
            MB_COMPOSITE,
            (char*)schars, //要转换的Ansi字符串
            -1, //自动计算长度
            0,
            0
            );
        CString tmpstr;
        tmpstr.GetBuffer(widecharlen); //为转换后保存Unicode字符串分配内存
        MultiByteToWideChar( //从Ansi转换到Unicode字符
            CP_ACP,
            MB_COMPOSITE,
            (char*)schars,
            -1,
            (LPWSTR)tmpstr.GetBuffer(widecharlen), //转换到tmpstr
            widecharlen //最多转换widecharlen个Unicode字符
            );
        wstr = tmpstr;
    }

    void TestFunction()
    {
        TCHAR abc[]=_T("ab我们的家ab");
        char b[15];
        MyWideCharToMultiByte(abc,b,sizeof(b));
        //  char c[]="ab如果cd就好了!abcdefg";
        CString str;
        MyMultiByteToWideChar(b,str);

        MyWideCharToMultiByte((LPWSTR)str.GetBuffer(0),b,sizeof(b));
    }

  • 相关阅读:
    阅读笔记06
    阅读笔记05
    学习进度03
    四则运算03
    阅读笔记04
    求最大子数组值(有环版)
    合作项目02
    新的小组信息以及项目名称与介绍
    第六周进度条
    软件工程个人作业4(课堂练习&&课堂作业)
  • 原文地址:https://www.cnblogs.com/Jade2009/p/1611384.html
Copyright © 2020-2023  润新知