zoukankan      html  css  js  c++  java
  • [VC++]CString转化成char

    CString   转化成  
    char*   之一:强制类型转换为   LPCTSTR;  
      
      
      这是一种略微硬性的转换,有关"正确"的做法,人们在认识上还存在许多混乱,正确的使用方法有很多,但错误的使用方法可能与正确的使用方法一样多。  
        我们首先要了解   CString   是一种很特殊的  
    C++   对象,它里面包含了三个值:一个指向某个数据缓冲区的指针、一个是该缓冲中有效的字符记数以及一个缓冲区长度。  
    有效字符数的大小可以是从0到该缓冲最大长度值减1之间的任何数(因为字符串结尾有一个NULL字符)。字符记数和缓冲区长度被巧妙隐藏。  
      
      除非你做一些特殊的操作,否则你不可能知道给CString对象分配的缓冲区的长度。这样,即使你获得了该0缓冲的地址,你也无法更改其中的内容,不能截短字符串,也  
    绝对没有办法加长它的内容,否则第一时间就会看到溢出。  
        LPCTSTR  
    操作符(或者更明确地说就是   TCHAR   *   操作符)在  
    CString   类中被重载了,该操作符的定义是返回缓冲区的地址,因此,如果你需要一个指向  
    CString   的   字符串指针的话,可以这样做:  
      
      
      CString  
    s("GrayCat");  
      LPCTSTR   p  
    =   s;  
      
      它可以正确地运行。这是由C语言的强制类型转化规则实现的。当需要强制类型转化时,C++规测容许这种选择。比如,你可以将(浮点数)定义为将某个复数  
    (有一对浮点数)进行强制类型转换后只返回该复数的第一个浮点数(也就是其实部)。可以象下面这样:  
      
      Complex   c(1.2f,  
    4.8f);  
      float   realpart  
    =   c;  
      
    如果(float)操作符定义正确的话,那么实部的的值应该是1.2。  
      
      这种强制转化适合所有这种情况,例如,任何带有   LPCTSTR  
    类型参数的函数都会强制执行这种转换。   于是,你可能有这样一个函数(也许在某个你买来的DLL中):  
      
      BOOL  
    DoSomethingCool(LPCTSTR   s);  
      
    你象下面这样调用它:  
      
      CString  
    file("c:\\myfiles\\coolstuff")  
      BOOL  
    result   =   DoSomethingCool(file);  
      
      它能正确运行。因为   DoSomethingCool   函数已经说明了需要一个  
    LPCTSTR   类型的参数,因此   LPCTSTR  
    被应用于该参数,在   MFC   中就是返回的串地址。  
      
      如果你要格式化字符串怎么办呢?  
      
      CString  
    graycat("GrayCat");  
      CString   s;  
      s.Format("Mew!   I   love  
    %s",   graycat);  
      
      注意由于在可变参数列表中的值(在函数说明中是以"..."表示的)并没有隐含一个强制类型转换操作符。你会得到什么结果呢?  
        一个令人惊讶的结果,我们得到的实际结果串是:  
      
      "Mew!   I   love  
    GrayCat"。  
        因为   MFC  
    的设计者们在设计   CString   数据类型时非常小心,  
    CString   类型表达式求值后指向了字符串,所以这里看不到任何象   Format  
    或   sprintf   中的强制类型转换,你仍然可以得到正确的行为。描述  
    CString   的附加数据实际上在   CString  
    名义地址之后。  
      
      有一件事情你是不能做的,那就是修改字符串。比如,你可能会尝试用","代替"."(不要做这样的,如果你在乎国际化问题,你应该使用十进制转换的  
    National   Language   Support  
    特性,),下面是个简单的例子:  
      
      
    CString   v("1.00");   //   货币金额,两位小数  
      LPCTSTR   p   =   v;  
      p[lstrlen(p)   -   3]   =  
    ,;  
        这时编译器会报错,因为你赋值了一个常量串。如果你做如下尝试,编译器也会错:  
      
      strcat(p,   "each");  
        因为   strcat   的第一个参数应该是  
    LPTSTR   类型的数据,而你却给了一个   LPCTSTR。  
      
        不要试图钻这个错误消息的牛角尖,这只会使你自己陷入麻烦!  
      
        原因是缓冲有一个计数,它是不可存取的(它位于  
    CString  
    地址之下的一个隐藏区域),如果你改变这个串,缓冲中的字符计数不会反映所做的修改。此外,如果字符串长度恰好是该字符串物理限制的长度(梢后还会讲到这个问题),那么扩展该字符串将改写缓冲以外的任何数据,那是你无权进行写操作的内存(不对吗?),你会毁换坏不属于你的内存。这是应用程序真正的死亡处方。  
      
      CString转化成char*   之二:使用  
    CString   对象的   GetBuffer   方法;  
      
        如果你需要修改   CString  
    中的内容,它有一个特殊的方法可以使用,那就是   GetBuffer,它的作用是返回一个可写的缓冲指针。  
    如果你只是打算修改字符或者截短字符串,你完全可以这样做:  
      
      
    CString   s(_T("File.ext"));  
      LPTSTR  
    p   =   s.GetBuffer();  
      
    LPTSTR   dot   =   strchr(p,  
    .);   //   OK,   should  
    have   used   s.Find...  
      
    if(p   !=   NULL)  
      *p  
    =   _T(\0);  
      s.ReleaseBuffer();  
        这是   GetBuffer  
    的第一种用法,也是最简单的一种,不用给它传递参数,它使用默认值  
    0,意思是:"给我这个字符串的指针,我保证不加长它"。当你调用   ReleaseBuffer  
    时,字符串的实际长度会被重新计算,然后存入   CString   对象中。  
        必须强调一点,在   GetBuffer   和  
    ReleaseBuffer   之间这个范围,一定不能使用你要操作的这个缓冲的  
    CString   对象的任何方法。因为   ReleaseBuffer  
    被调用之前,该   CString   对象的完整性得不到保障。研究以下代码:  
      
      CString   s(...);  
      
      LPTSTR   p   =  
    s.GetBuffer();  
      
      //...  
    这个指针   p   发生了很多事情  
      
      int   n   =  
    s.GetLength();   //   很糟D!!!!!  
    有可能给出错误的答案!!!  
      
      
    s.TrimRight();   //   很糟!!!!!  
    不能保证能正常工作!!!!  
      
      
    s.ReleaseBuffer();   //   现在应该   OK  
      
      int   m   =  
    s.GetLength();   //   这个结果可以保证是正确的。  
      
      s.TrimRight();   //  
    将正常工作。  
      
      假设你想增加字符串的长度,你首先要知道这个字符串可能会有多长,好比是声明字符串数组的时候用:  
      
      char   buffer[1024];  
      表示   1024   个字符空间足以让你做任何想做得事情。在  
    CString   中与之意义相等的表示法:  
      
      
    LPTSTR   p   =   s.GetBuffer(1024);  
        调用这个函数后,你不仅获得了字符串缓冲区的指针,而且同时还获得了长度至少为   1024  
    个字符的空间(注意,我说的是"字符",而不是"字节",因为   CString  
    是以隐含方式感知   Unicode   的)。  
      
      同时,还应该注意的是,如果你有一个常量串指针,这个串本身的值被存储在只读内存中,如果试图存储它,即使你已经调用了  
    GetBuffer   ,并获得一个只读内存的指针,存入操作会失败,并报告存取错误。我没有在  
    CString   上证明这一点,但我看到过大把的   C  
    程序员经常犯这个错误。  
        C  
    程序员有一个通病是分配一个固定长度的缓冲,对它进行   sprintf  
    操作,然后将它赋值给一个   CString:  
      
      
    char   buffer[256];  
      sprintf(buffer,  
    "%......",   args,   ...);   //  
    ...   部分省略许多细节  
      CString  
    s   =   buffer;  
      
    虽然更好的形式可以这么做:  
      
      CString  
    s;  
      s.Format(_T("%...."),   args,  
    ...);  
      如果你的字符串长度万一超过   256  
    个字符的时候,不会破坏堆栈。  
      
      
      另外一个常见的错误是:既然固定大小的内存不工作,那么就采用动态分配字节,这种做法弊端更大:  
      
      int   len   =  
    lstrlen(parm1)   +   13  
    lstrlen(parm2)   +   10   +  
    100;  
      
      char  
    *   buffer   =   new  
    char[len];  
      
      
    sprintf(buffer,   "%s   is   equal  
    to   %s,   valid   data",  
    parm1,   parm2);  
      
      
    CString   s   =   buffer;  
      
      ......  
      
      delete   []   buffer;  
      
    它可以能被简单地写成:  
      
      CString  
    s;  
      
      s.Format(_T("%s  
    is   equal   to   %s,  
    valid   data"),   parm1,   parm2);  
        需要注意   sprintf   例子都不是  
    Unicode   就绪的,尽管你可以使用   tsprintf   以及用  
    _T()   来包围格式化字符串,但是基本   思路仍然是在走弯路,这这样很容易出错。

     

  • 相关阅读:
    调用 验证码
    始终居中的弹出层
    jq常用
    ThinkPHP redirect 方法
    session 的生成和删除
    1355:字符串匹配问题(strs)
    1348:【例49】城市公交网建设问题
    1357:车厢调度(train)
    1358:中缀表达式值(expr)
    1351:【例412】家谱树
  • 原文地址:https://www.cnblogs.com/boneking/p/1337793.html
Copyright © 2011-2022 走看看