<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-17  評論-6  文章-1  trackbacks-0
      2007年4月17日
    find   basedir   -name   CVS   |xargs   rm   -rf  
    posted @ 2007-04-17 14:32 小鐵匠 閱讀(323) | 評論 (0)編輯 收藏
      2006年10月25日


    ??? public void doFilter(ServletRequest request, ServletResponse response,
    ??????????? FilterChain chain) throws IOException, ServletException {

    ??????? HttpServletRequest req = (HttpServletRequest) request;

    ??????? int length = req.getContentLength();
    ??????? if (length > 0) {
    ??????????? BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(req,length);

    ??????????? InputStream is = bufferedRequest.getInputStream();
    ??????????? byte[] content = new byte[length];
    ???????????
    ??????????? int pad = 0;
    ??????????? while(pad < length){
    ??????????????? pad += is.read(content, pad, length);
    ??????????? }

    ????????????request = bufferedRequest;
    ??????? }
    ??????? chain.doFilter(request, response);??????
    ??? }


    BufferedRequestWrapper .java

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;

    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;

    public class BufferedRequestWrapper extends HttpServletRequestWrapper {

    ??? ByteArrayInputStream bais;

    ??? BufferedServletInputStream bsis;

    ??? byte[] buffer;

    ??? public BufferedRequestWrapper(HttpServletRequest req,int length) throws IOException {
    ??????? super(req);
    ??????? // Read InputStream and store its content in a buffer.
    ??????? InputStream is = req.getInputStream();
    ??????? buffer = new byte[length];

    ??????? int pad = 0;
    ??????? while(pad < length){
    ??????????? pad += is.read(buffer, pad, length);
    ??????? }
    ??? }

    ??? public ServletInputStream getInputStream() {
    ??????? try {
    ??????????? // Generate a new InputStream by stored buffer
    ??????????? bais = new ByteArrayInputStream(buffer);
    ??????????? // Istantiate a subclass of ServletInputStream
    ??????????? // (Only ServletInputStream or subclasses of it are accepted by the
    ??????????? // servlet engine!)
    ??????????? bsis = new BufferedServletInputStream(bais);
    ??????? } catch (Exception ex) {
    ??????????? ex.printStackTrace();
    ??????? } finally {
    ??????? }
    ??????? return bsis;
    ??? }

    }




    BufferedServletInputStream .java

    import java.io.*;
    import javax.servlet.ServletInputStream;

    /*
    ?Subclass of ServletInputStream needed by the servlet engine.
    ?All inputStream methods are wrapped and are delegated to
    ?the ByteArrayInputStream (obtained as constructor parameter)!
    ?*/
    public class BufferedServletInputStream extends ServletInputStream {

    ??? ByteArrayInputStream bais;

    ??? public BufferedServletInputStream(ByteArrayInputStream bais) {
    ??????? this.bais = bais;
    ??? }

    ??? public int available() {
    ??????? return bais.available();
    ??? }

    ??? public int read() {
    ??????? return bais.read();
    ??? }

    ??? public int read(byte[] buf, int off, int len) {
    ??????? return bais.read(buf, off, len);
    ??? }

    }

    posted @ 2006-10-25 17:01 小鐵匠 閱讀(2739) | 評論 (1)編輯 收藏
      2006年7月10日
    $ gcc -o x11fred -L/usr/openwin/lib x11fred.c -lX11
    will compile and link a program called x11fred using the version of the library libX11 found in the
    /usr/openwin/lib directory.
    posted @ 2006-07-10 14:54 小鐵匠 閱讀(421) | 評論 (0)編輯 收藏
      2006年5月10日

    有發(fā)送人名稱中文支持,支持bytes格式附件,附件中文支持

    ? public static boolean send(String fromName, String fromAddr, String to, String subject, String
    ???????????????????????????? body, String fileName, byte[] file) throws
    ????? Exception {
    ??????? //發(fā)送人名稱,用base64編碼,再加上特殊標(biāo)志
    ??????? fromName = "=?GB2312?B?" + new String(base64.encode((fromName).getBytes()))? + "?=";
    ??? Properties props = new Properties();
    ??? Session session = Session.getInstance(props, null);
    ??? props.put("mail.smtp.host", Constants.mailhost);
    ??? props.put("mail.smtp.auth", "false");?
    ??? Message msg = new MimeMessage(session);
    ????? msg.setFrom(new InternetAddress(fromAddr,fromName));
    //后面的BodyPart將加入到此處創(chuàng)建的Multipart中
    ??? Multipart mp = new MimeMultipart();
    // Create the message part
    ??? BodyPart messageBodyPart = new MimeBodyPart();

    ??? // Fill the message
    ??? messageBodyPart.setText(body);

    ??? mp.addBodyPart(messageBodyPart);

    ????? /*發(fā)送附件*/
    ???? if (file != null && file.length > 0) {
    ?????? //利用枚舉器方便的遍歷集合
    ???????? MimeBodyPart mbp = new MimeBodyPart();?
    //???????? File fileTmp = null;
    ???????? //得到數(shù)據(jù)源
    //???????? FileDataSource fds = new FileDataSource(fileTmp);
    ???????? //得到附件本身并至入BodyPart
    ???????? mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(file,"application/octet-stream")));
    ???????? //得到文件名同樣至入BodyPart
    ???????? mbp.setFileName(MimeUtility.encodeWord(fileName,"GB2312",null));
    ???????? mp.addBodyPart(mbp);
    ???? }
    ???
    ??? //Multipart加入到信件
    ??? msg.setContent(mp);

    ??? msg.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
    ??? msg.setSubject(subject);

    ??? msg.setHeader("X-Mailer", "personal Email Sender");
    ??? msg.setSentDate(new Date());

    ??? Transport transport = session.getTransport("smtp");

    ??? //添加認(rèn)證信息
    ??? transport.connect(Constants.mailhost, Constants.user, Constants.pwd);
    ??? transport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO));
    ??? transport.close();
    ??? return true;
    ? }




    import java.io.*;
    import javax.activation.*;

    public class ByteArrayDataSource implements DataSource {
    ??? /** * Data to write. */
    ??? private byte[] _data;

    ??? /** * Content-Type. */
    ??? private String _type;

    ??? /* Create a datasource from an input stream */
    ??? public ByteArrayDataSource(InputStream is, String type) {
    ??????? _type = type;
    ??????? try {
    ??????????? ByteArrayOutputStream os = new ByteArrayOutputStream();
    ??????????? int ch;

    ??????????? // XXX : must be made more efficient by
    ??????????? // doing buffered reads, rather than one byte reads
    ??????????? while ((ch = is.read()) != -1)
    ??????????????? os.write(ch);
    ??????????? _data = os.toByteArray();
    ??????? } catch (IOException ioe) {
    ??????? }
    ??? }

    ??? /* Create a datasource from a byte array */
    ??? public ByteArrayDataSource(byte[] data, String type) {
    ??????? _data = data;
    ??????? _type = type;
    ??? }

    ??? /* Create a datasource from a String */
    ??? public ByteArrayDataSource(String data, String type) {
    ??????? try {
    ??????????? // Assumption that the string contains only ascii
    ??????????? // characters ! Else just pass in a charset into this
    ??????????? // constructor and use it in getBytes()
    ??????????? _data = data.getBytes("iso-8859-1");
    ??????? } catch (UnsupportedEncodingException uee) {
    ??????? }
    ??????? _type = type;
    ??? }

    ??? public InputStream getInputStream() throws IOException {
    ??????? if (_data == null)
    ??????????? throw new IOException("no data");
    ??????? return new ByteArrayInputStream(_data);
    ??? }

    ??? public OutputStream getOutputStream() throws IOException {
    ??????? throw new IOException("cannot do this");
    ??? }

    ??? public String getContentType() {
    ??????? return _type;
    ??? }

    ??? public String getName() {
    ??????? return "dummy";
    ??? }
    }

    posted @ 2006-05-10 18:02 小鐵匠 閱讀(642) | 評論 (1)編輯 收藏
      2006年3月9日
    C/C++頭文件一覽

    C、傳統(tǒng) C++

    #include <assert.h>    //設(shè)定插入點(diǎn)
    #include <ctype.h>     //字符處理
    #include <errno.h>     //定義錯誤碼
    #include <float.h>     //浮點(diǎn)數(shù)處理
    #include <fstream.h>    //文件輸入/輸出
    #include <iomanip.h>    //參數(shù)化輸入/輸出
    #include <iostream.h>   //數(shù)據(jù)流輸入/輸出
    #include <limits.h>    //定義各種數(shù)據(jù)類型最值常量
    #include <locale.h>    //定義本地化函數(shù)
    #include <math.h>     //定義數(shù)學(xué)函數(shù)
    #include <stdio.h>     //定義輸入/輸出函數(shù)
    #include <stdlib.h>    //定義雜項函數(shù)及內(nèi)存分配函數(shù)
    #include <string.h>    //字符串處理
    #include <strstrea.h>   //基于數(shù)組的輸入/輸出
    #include <time.h>     //定義關(guān)于時間的函數(shù)
    #include <wchar.h>     //寬字符處理及輸入/輸出
    #include <wctype.h>    //寬字符分類

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

    標(biāo)準(zhǔn) C++ (同上的不再注釋)

    #include <algorithm>    //STL 通用算法
    #include <bitset>     //STL 位集容器
    #include <cctype>
    #include <cerrno>
    #include <clocale>
    #include <cmath>
    #include <complex>     //復(fù)數(shù)類
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
    #include <deque>      //STL 雙端隊列容器
    #include <exception>    //異常處理類
    #include <fstream>
    #include <functional>   //STL 定義運(yùn)算函數(shù)(代替運(yùn)算符)
    #include <limits>
    #include <list>      //STL 線性列表容器
    #include <map>       //STL 映射容器
    #include <iomanip>
    #include <ios>       //基本輸入/輸出支持
    #include <iosfwd>     //輸入/輸出系統(tǒng)使用的前置聲明
    #include <iostream>
    #include <istream>     //基本輸入流
    #include <ostream>     //基本輸出流
    #include <queue>      //STL 隊列容器
    #include <set>       //STL 集合容器
    #include <sstream>     //基于字符串的流
    #include <stack>      //STL 堆棧容器    
    #include <stdexcept>    //標(biāo)準(zhǔn)異常類
    #include <streambuf>    //底層輸入/輸出支持
    #include <string>     //字符串類
    #include <utility>     //STL 通用模板類
    #include <vector>     //STL 動態(tài)數(shù)組容器
    #include <cwchar>
    #include <cwctype>

    using namespace std;

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

    C99 增加

    #include <complex.h>   //復(fù)數(shù)處理
    #include <fenv.h>    //浮點(diǎn)環(huán)境
    #include <inttypes.h>  //整數(shù)格式轉(zhuǎn)換
    #include <stdbool.h>   //布爾環(huán)境
    #include <stdint.h>   //整型環(huán)境
    #include <tgmath.h>   //通用類型數(shù)學(xué)宏

    posted @ 2006-03-09 16:55 小鐵匠 閱讀(532) | 評論 (0)編輯 收藏
    string.h中的函數(shù)

    @函數(shù)名稱:   strdup
    函數(shù)原型:   char *strdup(const char *s)
    函數(shù)功能:   字符串拷貝,目的空間由該函數(shù)分配
    函數(shù)返回:   指向拷貝后的字符串指針
    參數(shù)說明:   src-待拷貝的源字符串
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    #include <alloc.h>
    int main()
    {
      char *dup_str, *string="abcde";
      dup_str=strdup(string);
      printf("%s", dup_str);
      free(dup_str);
      return 0;
    }


    @函數(shù)名稱:   strcpy
    函數(shù)原型:   char* strcpy(char* str1,char* str2);
    函數(shù)功能:   把str2指向的字符串拷貝到str1中去
    函數(shù)返回:   返回str1,即指向str1的指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char string[10];
      char *str1="abcdefghi";
      strcpy(string,str1);
      printf("the string is:%s\n",string);
      return 0;
    }


    @函數(shù)名稱:   strncpy
    函數(shù)原型:   char *strncpy(char *dest, const char *src,int count)
    函數(shù)功能:   將字符串src中的count個字符拷貝到字符串dest中去
    函數(shù)返回:   指向dest的指針
    參數(shù)說明:   dest-目的字符串,src-源字符串,count-拷貝的字符個數(shù)
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char string[10];
      char *str1="abcdefghi";
      strncpy(string,str1,3);
      string[3]='\0';
      printf("%s",string);
      return 0;
    }


    @函數(shù)名稱:   strcat
    函數(shù)原型:   char* strcat(char * str1,char * str2);
    函數(shù)功能:   把字符串str2接到str1后面,str1最后的'\0'被取消
    函數(shù)返回:   str1
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>

    int main()
    {
      char buffer[80];

      strcpy(buffer,"Hello ");
      strcat(buffer,"world");
      printf("%s\n",buffer);
      return 0;
    }


    @函數(shù)名稱:   strncat
    函數(shù)原型:   char *strncat(char *dest, const char *src, size_t maxlen)
    函數(shù)功能:   將字符串src中前maxlen個字符連接到dest中
    函數(shù)返回:
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>

    char buffer[80];

    int main()
    {
      strcpy(buffer,"Hello ");
      strncat(buffer,"world",8);
      printf("%s\n",buffer);
      strncat(buffer,"*************",4);
      printf("%s\n",buffer);
      return 0;
    }


    @函數(shù)名稱:   strcmp
    函數(shù)原型:   int strcmp(char * str1,char * str2);
    函數(shù)功能:   比較兩個字符串str1,str2.
    函數(shù)返回:   str1<str2,返回負(fù)數(shù); str1=str2,返回 0; str1>str2,返回正數(shù).
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      char *buf1="aaa", *buf2="bbb", *buf3="ccc";
      int ptr;
      ptr=strcmp(buf2, buf1);
      if(ptr>0)
        printf("buffer 2 is greater than buffer 1\n");
      else
        printf("buffer 2 is less than buffer 1\n");
      ptr=strcmp(buf2, buf3);
      if(ptr>0)
        printf("buffer 2 is greater than buffer 3\n");
      else
        printf("buffer 2 is less than buffer 3\n");
      return 0;
    }


    @函數(shù)名稱:   strncmp
    函數(shù)原型:   int strncmp(char *str1,char *str2,int count)
    函數(shù)功能:   對str1和str2中的前count個字符按字典順序比較
    函數(shù)返回:   小于0:str1<str2,等于0:str1=str2,大于0:str1>str2
    參數(shù)說明:   str1,str2-待比較的字符串,count-比較的長度
    所屬文件:   <string.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      int ptr;
      char *buf1="aaabbb",*buf2="bbbccc",*buf3="ccc";
      ptr=strncmp(buf2,buf1,3);
      if (ptr>0)
        printf("buffer 2 is greater than buffer 1");
      else
        printf("buffer 2 is less than buffer 1");
        ptr=strncmp(buf2,buf3,3);
      if (ptr>0)
        printf("buffer 2 is greater than buffer 3");
      else
        printf("buffer 2 is less than buffer 3");
      return(0);
    }


    @函數(shù)名稱:   strpbrk
    函數(shù)原型:   char *strpbrk(const char *s1, const char *s2)
    函數(shù)功能:   得到s1中第一個“同時也出現(xiàn)在s2中”字符的位置指針
    函數(shù)返回:   位置指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
    char *p="Find all vowels";

    while(p)
    {
      printf("%s\n",p);
      p=strpbrk(p+1,"aeiouAEIOU");
    }
    return 0;
    }


    @函數(shù)名稱:   strcspn
    函數(shù)原型:   int strcspn(const char *s1, const char *s2)
    函數(shù)功能:   統(tǒng)計s1中從頭開始直到第一個“來自s2中的字符”出現(xiàn)的長度
    函數(shù)返回:   長度
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>

    int main()
    {
      printf("%d\n",strcspn("abcbcadef","cba"));
      printf("%d\n",strcspn("xxxbcadef","cba"));
      printf("%d\n",strcspn("123456789","cba"));
      return 0;
    }


    @函數(shù)名稱:   strspn
    函數(shù)原型:   int strspn(const char *s1, const char *s2)
    函數(shù)功能:   統(tǒng)計s1中從頭開始直到第一個“不來自s2中的字符”出現(xiàn)的長度
    函數(shù)返回:   位置指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    #include <alloc.h>
    int main()
    {
      printf("%d\n",strspn("out to lunch","aeiou"));
      printf("%d\n",strspn("out to lunch","xyz"));
      return 0;
    }


    @函數(shù)名稱:   strchr
    函數(shù)原型:   char* strchr(char* str,char ch);
    函數(shù)功能:   找出str指向的字符串中第一次出現(xiàn)字符ch的位置
    函數(shù)返回:   返回指向該位置的指針,如找不到,則返回空指針
    參數(shù)說明:   str-待搜索的字符串,ch-查找的字符
    所屬文件:   <string.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      char string[15];
      char *ptr, c='r';
      strcpy(string, "This is a string");
      ptr=strchr(string, c);
      if (ptr)
        printf("The character %c is at position: %d\n",c,ptr-string);
      else
        printf("The character was not found\n");
      return 0;
    }


    @函數(shù)名稱:   strrchr
    函數(shù)原型:   char *strrchr(const char *s, int c)
    函數(shù)功能:   得到字符串s中最后一個含有c字符的位置指針
    函數(shù)返回:   位置指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      char string[15];
      char *ptr,c='r';
      strcpy(string,"This is a string");
      ptr=strrchr(string,c);
      if (ptr)
        printf("The character %c is at position:%d",c,ptr-string);
      else
        printf("The character was not found");
      return 0;
    }


    @函數(shù)名稱:   strstr
    函數(shù)原型:   char* strstr(char* str1,char* str2);
    函數(shù)功能:   找出str2字符串在str1字符串中第一次出現(xiàn)的位置(不包括str2的串結(jié)束符)
    函數(shù)返回:   返回該位置的指針,如找不到,返回空指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char *str1="Open Watcom C/C++",*str2="Watcom",*ptr;
      ptr=strstr(str1,str2);
      printf("The substring is:%s\n",ptr);
      return 0;
    }


    @函數(shù)名稱:   strrev
    函數(shù)原型:   char *strrev(char *s)
    函數(shù)功能:   將字符串中的所有字符顛倒次序排列
    函數(shù)返回:   指向s的指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      char *forward="string";
      printf("Before strrev():%s",forward);
      strrev(forward);
      printf("After strrev(): %s",forward);
      return 0;
    }


    @函數(shù)名稱:   strnset
    函數(shù)原型:   char *strnset(char *s, int ch, size_t n)
    函數(shù)功能:   將字符串s中前n個字符設(shè)置為ch的值
    函數(shù)返回:   指向s的指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char *string="abcdefghijklmnopqrstuvwxyz";
      char letter='x';
      printf("string before strnset: %s",string);
      strnset(string,letter,13);
      printf("string after strnset: %s",string);
      return 0;
    }


    @函數(shù)名稱:   strset
    函數(shù)原型:   char *strset(char *s, int ch)
    函數(shù)功能:   將字符串s中所有字符設(shè)置為ch的值
    函數(shù)返回:   指向s的指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char string[10]="123456789";
      char symbol='c';
      printf("Before strset(): %s", string);
      strset(string, symbol);
      printf("After strset(): %s", string);
      return 0;
    }


    @函數(shù)名稱:   strtok
    函數(shù)原型:   char *strtok(char *s1, const char *s2)
    函數(shù)功能:   分解s1字符串為用特定分隔符分隔的多個字符串(一般用于將英文句分解為單詞)
    函數(shù)返回:   字符串s1中首次出現(xiàn)s2中的字符前的子字符串指針
    參數(shù)說明:   s2一般設(shè)置為s1中的分隔字符
            規(guī)定進(jìn)行子調(diào)用時(即分割s1的第二、三及后續(xù)子串)第一參數(shù)必須是NULL
            在每一次匹配成功后,將s1中分割出的子串位置替換為NULL(摘下鏈中第一個環(huán)),因此s1被破壞了
            函數(shù)會記憶指針位置以供下一次調(diào)用
           
    所屬文件:   <string.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      char *p;
      char *buffer;
      char *delims={ " .," };

      buffer=strdup("Find words, all of them.");
      printf("%s\n",buffer);
      p=strtok(buffer,delims);
      while(p!=NULL){
        printf("word: %s\n",p);
        p=strtok(NULL,delims);
      }
      printf("%s\n",buffer);
      return 0;
    }


    @函數(shù)名稱:   strupr
    函數(shù)原型:   char *strupr(char *s)
    函數(shù)功能:   將字符串s中的字符變?yōu)榇髮?BR>函數(shù)返回:
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char *string="abcdefghijklmnopqrstuvwxyz",*ptr;
      ptr=strupr(string);
      printf("%s",ptr);
      return 0;
    }


    @函數(shù)名稱:   strlwr
    函數(shù)原型:   char *strlwr(char *s)
    函數(shù)功能:   將字符串中的字符變?yōu)樾懽址?BR>函數(shù)返回:   指向s的指針
    參數(shù)說明:
    所屬文件:   <string.h>

    #include<string.h>
    int main()
    {
      char str[]="HOW TO SAY?";
      printf("%s",strlwr(str));
      return 0;
    }


    @函數(shù)名稱:   strlen
    函數(shù)原型:   unsigned int strlen(char * str);
    函數(shù)功能:   統(tǒng)計字符串str中字符的個數(shù)(不包括終止符'\0')
    函數(shù)返回:   返回字符串的長度.
    參數(shù)說明:
    所屬文件:   <string.h>

    #include <stdio.h>
    #include<string.h>
    int main()
    {
      char str[]="how are you!";
      printf("the lence is:%d\n",strlen(str));
      return 0;
    }


    @函數(shù)名稱:   strerror
    函數(shù)原型:   char *strerror(int errnum)
    函數(shù)功能:   得到錯誤信息的內(nèi)容信息
    函數(shù)返回:   錯誤提示信息字符串指針
    參數(shù)說明:   errnum-錯誤編號
    所屬文件:   <string.h>

    #include <stdio.h>
    #include <errno.h>
    int main()
    {
      char *buffer;
      buffer=strerror(errno);
      printf("Error: %s",buffer);
      return 0;
    }


    @函數(shù)名稱:   memcpy
    函數(shù)原型:   void *memcpy(void *dest, const void *src, size_t n)
    函數(shù)功能:   字符串拷貝
    函數(shù)返回:   指向dest的指針
    參數(shù)說明:   src-源字符串,n-拷貝的最大長度
    所屬文件:   <string.h>,<mem.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char src[]="******************************";
      char dest[]="abcdefghijlkmnopqrstuvwxyz0123456709";
      char *ptr;
      printf("destination before memcpy:%s\n",dest);
      ptr=memcpy(dest,src,strlen(src));
      if (ptr)
        printf("destination after memcpy:%s\n",dest);
      else
        printf("memcpy failed");
      return 0;
    }


    @函數(shù)名稱:   memccpy
    函數(shù)原型:   void *memccpy(void *dest, const void *src, int c, size_t n)
    函數(shù)功能:   字符串拷貝,到指定長度或遇到指定字符時停止拷貝
    函數(shù)返回:
    參數(shù)說明:   src-源字符串指針,c-中止拷貝檢查字符,n-長度,dest-拷貝底目的字符串指針
    所屬文件:   <string.h>,<mem.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      char *src="This is the source string";
      char dest[50];
      char *ptr;
      ptr=memccpy(dest,src,'c',strlen(src));
      if (ptr)
      {
        *ptr='\0';
        printf("The character was found:%s",dest);
      }
      else
        printf("The character wasn't found");
      return 0;
    }


    @函數(shù)名稱:   memchr
    函數(shù)原型:   void *memchr(const void *s, int c, size_t n)
    函數(shù)功能:   在字符串中第開始n個字符中尋找某個字符c的位置
    函數(shù)返回:   返回c的位置指針,返回NULL時表示未找到
    參數(shù)說明:   s-要搜索的字符串,c-要尋找的字符,n-指定長度
    所屬文件:   <string.h>,<mem.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      char str[17];
      char *ptr;
      strcpy(str,"This is a string");
      ptr=memchr(str,'r',strlen(str));
      if (ptr)
      printf("The character 'r' is at position: %d",ptr-str);
      else
      printf("The character was not found");
      return 0;
    }


    @函數(shù)名稱:   memcmp
    函數(shù)原型:   int memcmp(const void *s1, const void *s2,size_t n)
    函數(shù)功能:   按字典順序比較兩個串s1和s2的前n個字節(jié)
    函數(shù)返回:   <0,=0,>0分別表示s1<,=,>s2
    參數(shù)說明:   s1,s2-要比較的字符串,n-比較的長度
    所屬文件:   <string.h>,<mem.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char *buf1="ABCDE123";
      char *buf2="abcde456";
      int stat;
      stat=memcmp(buf1,buf2,5);
      printf("The strings to position 5 are ");
      if(stat) printf("not ");
      printf("the same\n");
      return 0;
    }



    @函數(shù)名稱:   memicmp
    函數(shù)原型:   int memicmp(const void *s1, const void *s2, size_t n)
    函數(shù)功能:   按字典順序、不考慮字母大小寫對字符串s1,s2前n個字符比較
    函數(shù)返回:   <0,=0,>0分別表示s1<,=,>s2
    參數(shù)說明:   s1,s2-要比較的字符串,n-比較的長度
    所屬文件:   <string.h>,<mem.h>

    #include <stdio.h>
    #include <string.h>
    int main()
    {
      char *buf1="ABCDE123";
      char *buf2="abcde456";
      int stat;
      stat=memicmp(buf1,buf2,5);
      printf("The strings to position 5 are ");
      if(stat) printf("not");
      printf("the same");
      return 0;
    }


    @函數(shù)名稱:   memmove
    函數(shù)原型:   void *memmove(void *dest, const void *src, size_t n)
    函數(shù)功能:   字符串拷貝
    函數(shù)返回:   指向dest的指針
    參數(shù)說明:   src-源字符串,n-拷貝的最大長度
    所屬文件:   <string.h>,<mem.h>

    #include <string.h>
    #include <stdio.h>
    int main()
    {
      char dest[40]="abcdefghijklmnopqrstuvwxyz0123456789";
      printf("destination prior to memmove:%s\n",dest);
      memmove(dest+1,dest,35);
      printf("destination after memmove:%s",dest);
      return 0;
    }


    @函數(shù)名稱:   memset
    函數(shù)原型:   void *memset(void *s, int c, size_t n)
    函數(shù)功能:   字符串中的n個字節(jié)內(nèi)容設(shè)置為c
    函數(shù)返回:
    參數(shù)說明:   s-要設(shè)置的字符串,c-設(shè)置的內(nèi)容,n-長度
    所屬文件:   <string.h>,<mem.h>

    #include <string.h>
    #include <stdio.h>
    #include <mem.h>
    int main()
    {
      char buffer[]="Hello world";
      printf("Buffer before memset:%s\n",buffer);
      memset(buffer,'*',strlen(buffer)-1);
      printf("Buffer after memset:%s",buffer);
      return 0;
    }

    posted @ 2006-03-09 16:54 小鐵匠 閱讀(2007) | 評論 (0)編輯 收藏

    C++字符串完全指南 - Win32字符編碼(一)

    前言

    字符串的表現(xiàn)形式各異,象TCHAR,std::string,BSTR等等,有時還會見到怪怪的用_tcs起頭的宏。這個指南的目的就是說明各種字符串類型及其用途,并說明如何在必要時進(jìn)行類型的相互轉(zhuǎn)換。

    在指南的第一部分,介紹三種字符編碼格式。理解編碼的工作原理是致為重要的。即使你已經(jīng)知道字符串是一個字符的數(shù)組這樣的概念,也請閱讀本文,它會讓你明白各種字符串類之間的關(guān)系。

    指南的第二部分,將闡述各個字符串類,什么時候使用哪種字符串類,及其相互轉(zhuǎn)換。

    字符串基礎(chǔ) - ASCII, DBCS, Unicode

    所有的字符串類都起源于C語言的字符串,而C語言字符串則是字符的數(shù)組。首先了解一下字符類型。有三種編碼方式和三種字符類型。

    第一種編碼方式是單字節(jié)字符集,稱之為SBCS,它的所有字符都只有一個字節(jié)的長度。ASCII碼就是SBCS。SBCS字符串由一個零字節(jié)結(jié)尾。

    第二種編碼方式是多字節(jié)字符集,稱之為MBCS,它包含的字符中有單字節(jié)長的字符,也有多字節(jié)長的字符。Windows用到的MBCS只有二種字符類型,單字節(jié)字符和雙字節(jié)字符。因此Windows中用得最多的字符是雙字節(jié)字符集,即DBCS,通常用它來代替MBCS。

    在DBCS編碼中,用一些保留值來指明該字符屬于雙字節(jié)字符。例如,Shift-JIS(通用日語)編碼中,值0x81-0x9F 和 0xE0-0xFC 的意思是:“這是一個雙字節(jié)字符,下一個字節(jié)是這個字符的一部分”。這樣的值通常稱為前導(dǎo)字節(jié)(lead byte),總是大于0x7F。前導(dǎo)字節(jié)后面是跟隨字節(jié)(trail byte)。DBCS的跟隨字節(jié)可以是任何非零值。與SBCS一樣,DBCS字符串也由一個零字節(jié)結(jié)尾。

    第三種編碼方式是Unicode。Unicode編碼標(biāo)準(zhǔn)中的所有字符都是雙字節(jié)長。有時也將Unicode稱為寬字符集(wide characters),因為它的字符比單字節(jié)字符更寬(使用更多內(nèi)存)。注意,Unicode不是MBCS - 區(qū)別在于MBCS編碼中的字符長度是不同的。Unicode字符串用二個零字節(jié)字符結(jié)尾(一個寬字符的零值編碼)。

    單字節(jié)字符集是拉丁字母,重音文字,用ASCII標(biāo)準(zhǔn)定義,用于DOS操作系統(tǒng)。雙字節(jié)字符集用于東亞和中東語言。Unicode用于COM和Windows NT內(nèi)部。

    讀者都很熟悉單字節(jié)字符集,它的數(shù)據(jù)類型是char。雙字節(jié)字符集也使用char數(shù)據(jù)類型(雙字節(jié)字符集中的許多古怪處之一)。Unicode字符集用wchar_t數(shù)據(jù)類型。Unicode字符串用L前綴起頭,如:

      wchar_t  wch = L'1';      // 2 個字節(jié), 0x0031

      wchar_t* wsz = L"Hello";  // 12 個字節(jié), 6 個寬字符

    字符串的存儲

    單字節(jié)字符串順序存放各個字符,并用零字節(jié)表示字符串結(jié)尾。例如,字符串"Bob"的存儲格式為:

    Unicode編碼中,L"Bob"的存儲格式為:

    用0x0000 (Unicode的零編碼)結(jié)束字符串。

    DBCS 看上去有點(diǎn)象SBCS。以后我們會看到在串處理和指針使用上是有微妙差別的。字符串"日本語" (nihongo) 的存儲格式如下(用LB和TB分別表示前導(dǎo)字節(jié)和跟隨字節(jié)):

    注意,"ni"的值不是WORD值0xFA93。值93和FA順序組合編碼為字符"ni"。(在高位優(yōu)先CPU中,存放順序正如上所述)。

    字符串處理函數(shù)

    C語言字符串處理函數(shù),如strcpy(), sprintf(), atol()等只能用于單字節(jié)字符串。在標(biāo)準(zhǔn)庫中有只用于Unicode字符串的函數(shù),如wcscpy(), swprintf(), _wtol()。

    微軟在C運(yùn)行庫(CRT)中加入了對DBCS字符串的支持。對應(yīng)于strxxx()函數(shù),DBCS使用_mbsxxx()函數(shù)。在處理DBCS字符串(如日語,中文,或其它DBCS)時,就要用_mbsxxx()函數(shù)。這些函數(shù)也能用于處理SBCS字符串(因為DBCS字符串可能就只含有單字節(jié)字符)。

    現(xiàn)在用一個示例來說明字符串處理函數(shù)的不同。如有Unicode字符串L"Bob":

    x86 CPU的排列順序是低位優(yōu)先(little-endian)的,值0x0042的存儲順序為42 00。這時如用strlen()函數(shù)求字符串的長度就發(fā)生問題。函數(shù)找到第一個字節(jié)42,然后是00,意味著字符串結(jié)尾,于是返回1。反之,用wcslen()函數(shù)求"Bob"的長度更糟糕。wcslen()首先找到0x6F42,然后是0x0062,以后就在內(nèi)存緩沖內(nèi)不斷地尋找00 00直至發(fā)生一般性保護(hù)錯(GPF)。

    strxxx()及其對應(yīng)的_mbsxxx()究竟是如何運(yùn)作的?二者之間的不同是非常重要的,直接影響到正確遍歷DBCS字符串的方法。下面先介紹字符串遍歷,然后再回來討論strxxx()和 _mbsxxx()。

    字符串遍歷

    我們中的大多數(shù)人都是從SBCS成長過來的,都習(xí)慣于用指針的 ++ 和 -- 操作符來遍歷字符串,有時也使用數(shù)組來處理字符串中的字符。這二種方法對于SBCS 和 Unicode 字符串的操作都是正確無誤的,因為二者的字符都是等長的,編譯器能夠的正確返回我們尋求的字符位置。

    但對于DBCS字符串就不能這樣了。用指針訪問DBCS字符串有二個原則,打破這二個原則就會造成錯誤。

    1. 不可使用 ++ 算子,除非每次都檢查是否為前導(dǎo)字節(jié)。

    2. 絕不可使用 -- 算子來向后遍歷。

    先說明原則2,因為很容易找到一個非人為的示例。假設(shè),有一個配制文件,程序啟動時要從安裝路徑讀取該文件,如:C:\Program Files\MyCoolApp\config.bin。文件本身是正常的。

    假設(shè)用以下代碼來配制文件名:

    bool GetConfigFileName ( char* pszName, size_t nBuffSize )
    {
    char szConfigFilename[MAX_PATH];
        // 這里從注冊表讀取文件的安裝路徑,假設(shè)一切正常。
        // 如果路徑末尾沒有反斜線,就加上反斜線。
        // 首先,用指針指向結(jié)尾零:
    char* pLastChar = strchr ( szConfigFilename, '\0' );
        // 然后向后退一個字符:
        pLastChar--;  
        if ( *pLastChar != '\\' )
            strcat ( szConfigFilename, "\\" );
        // 加上文件名:
        strcat ( szConfigFilename, "config.bin" );
        // 如果字符串長度足夠,返回文件名:
        if ( strlen ( szConfigFilename ) >= nBuffSize )
            return false;
        else
            {
            strcpy ( pszName, szConfigFilename );
            return true;
            }
    }

    這段代碼的保護(hù)性是很強(qiáng)的,但用到DBCS字符串還是會出錯。假如文件的安裝路徑用日語表達(dá):C:\ヨウユソ,該字符串的內(nèi)存表達(dá)為:

    這時用上面的GetConfigFileName()函數(shù)來檢查文件路徑末尾是否含有反斜線就會出錯,得到錯誤的文件名。

    錯在哪里?注意上面的二個十六進(jìn)制值0x5C(藍(lán)色)。前面的0x5C是字符"\",后面則是字符值83 5C,代表字符"ソ"。可是函數(shù)把它誤認(rèn)為反斜線了。

    正確的方法是用DBCS函數(shù)將指針指向恰當(dāng)?shù)淖址恢茫缦滤荆?/P>

    bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize )
    {
    char szConfigFilename[MAX_PATH];
        // 這里從注冊表讀取文件的安裝路徑,假設(shè)一切正常。
        // 如果路徑末尾沒有反斜線,就加上反斜線。
        // 首先,用指針指向結(jié)尾零:
    char* pLastChar = _mbschr ( szConfigFilename, '\0' );
        // 然后向后退一個雙字節(jié)字符:
        pLastChar = CharPrev ( szConfigFilename, pLastChar );
        if ( *pLastChar != '\\' )
            _mbscat ( szConfigFilename, "\\" );
        // 加上文件名:
        _mbscat ( szConfigFilename, "config.bin" );
        // 如果字符串長度足夠,返回文件名:
        if ( _mbslen ( szInstallDir ) >= nBuffSize )
            return false;
        else
            {
            _mbscpy ( pszName, szConfigFilename );
            return true;
            }
    } 

    這個改進(jìn)的函數(shù)用CharPrev() API 函數(shù)將指針pLastChar向后移動一個字符。如果字符串末尾的字符是雙字節(jié)字符,就向后移動2個字節(jié)。這時返回的結(jié)果是正確的,因為不會將字符誤判為反斜線。

    現(xiàn)在可以想像到第一原則了。例如,要遍歷字符串尋找字符":",如果不使用CharNext()函數(shù)而使用++算子,當(dāng)跟隨字節(jié)值恰好也是":"時就會出錯。

    與原則2相關(guān)的是數(shù)組下標(biāo)的使用:

     2a. 絕不可在字符串?dāng)?shù)組中使用遞減下標(biāo)。

    出錯原因與原則2相同。例如,設(shè)置指針pLastChar為:

    char* pLastChar = &szConfigFilename [strlen(szConfigFilename) - 1];

    結(jié)果與原則2的出錯一樣。下標(biāo)減1就是指針向后移動一個字節(jié),不符原則2。

    再談strxxx() _mbsxxx()

    現(xiàn)在可以清楚為什么要用 _mbsxxx() 函數(shù)了。strxxx() 函數(shù)不認(rèn)識DBCS字符而 _mbsxxx()認(rèn)識。如果調(diào)用strrchr("C:\\", '\\')函數(shù)可能會出錯,但 _mbsrchr()認(rèn)識雙字節(jié)字符,所以能返回指向最后出現(xiàn)反斜線字符的指針位置。

    最后提一下strxxx() 和 _mbsxxx() 函數(shù)族中的字符串長度測量函數(shù),它們都返回字符串的字節(jié)數(shù)。如果字符串含有3個雙字節(jié)字符,_mbslen()將返回6。而Unicode的函數(shù)返回的是wchar_ts的數(shù)量,如wcslen(L"Bob") 返回3

    C++字符串完全指南 - Win32字符編碼(二)
    翻譯:連波
    15/11/2002
    URL: http://www.zdnet.com.cn/developer/tech/story/0,2000081602,39098306,00.htm

    Win32 API中的MBCS Unicode

    API的二個字符集

    也許你沒有注意到,Win32的API和消息中的字符串處理函數(shù)有二種,一種為MCBS字符串,另一種為Unicode字符串。例如,Win32中沒有SetWindowText()這樣的接口,而是用SetWindowTextA()和 SetWindowTextW()函數(shù)。后綴A (表示ANSI)指明是MBCS函數(shù),后綴W(表示寬字符)指明是Unicode函數(shù)。

    編寫Windows程序時,可以選擇用MBCS或Unicode API接口函數(shù)。用VC AppWizards向?qū)r,如果不修改預(yù)處理器設(shè)置,缺省使用的是MBCS函數(shù)。但是在API接口中沒有SetWindowText()函數(shù),該如何調(diào)用呢?實際上,在winuser.h頭文件中做了以下定義:

    BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString );
    BOOL WINAPI SetWindowTextW ( HWND hWnd, LPCWSTR lpString );
    #ifdef UNICODE
     #define SetWindowText  SetWindowTextW
    #else
     #define SetWindowText  SetWindowTextA
    #endif

    編寫MBCS應(yīng)用時,不必定義UNICODE,預(yù)處理為:

    #define SetWindowText  SetWindowTextA

    然后將SetWindowText()處理為真正的API接口函數(shù)SetWindowTextA() (如果愿意的話,可以直接調(diào)用SetWindowTextA() 或SetWindowTextW()函數(shù),不過很少有此需要)。

    如果要將缺省應(yīng)用接口改為Unicode,就到預(yù)處理設(shè)置的預(yù)處理標(biāo)記中去掉 _MBCS標(biāo)記,加入UNICODE 和 _UNICODE (二個標(biāo)記都要加入,不同的頭文件使用不同的標(biāo)記)。不過,這時要處理普通字符串反而會遇到問題。如有代碼:

    HWND hwnd = GetSomeWindowHandle();
    char szNewText[] = "we love Bob!";
    SetWindowText ( hwnd, szNewText );

    編譯器將"SetWindowText"置換為"SetWindowTextW"后,代碼變?yōu)椋?/P>

    HWND hwnd = GetSomeWindowHandle();
    char szNewText[] = "we love Bob!";
    SetWindowTextW ( hwnd, szNewText );

    看出問題了吧,這里用一個Unicode字符串處理函數(shù)來處理單字節(jié)字符串。

    第一種解決辦法是使用宏定義:
    HWND hwnd = GetSomeWindowHandle();
    #ifdef UNICODE
     wchar_t szNewText[] = L"we love Bob!";
    #else
     char szNewText[] = "we love Bob!";
    #endif
    SetWindowText ( hwnd, szNewText );

    要對每一個字符串都做這樣的宏定義顯然是令人頭痛的。所以用TCHAR來解決這個問題:

    TCHAR的救火角色

    TCHAR 是一種字符類型,適用于MBCS 和 Unicode二種編碼。程序中也不必到處使用宏定義。

    TCHAR的宏定義如下:

    #ifdef UNICODE
     typedef wchar_t TCHAR;
    #else
     typedef char TCHAR;
    #endif

    所以,TCHAR中在MBCS程序中是char類型,在Unicode中是 wchar_t 類型。

    對于Unicode字符串,還有個 _T() 宏,用于解決 L 前綴:

    #ifdef UNICODE
     #define _T(x) L##x
    #else
     #define _T(x) x
    #endif

    ## 是預(yù)處理算子,將二個變量粘貼在一起。不管什么時候都對字符串用 _T 宏處理,這樣就可以在Unicode編碼中給字符串加上L前綴,如:

    TCHAR szNewText[] = _T("we love Bob!");

    SetWindowTextA/W 函數(shù)族中還有其它隱藏的宏可以用來代替strxxx() 和 _mbsxxx() 字符串函數(shù)。例如,可以用 _tcsrchr 宏取代strrchr(),_mbsrchr(),或 wcsrchr()函數(shù)。_tcsrchr 根據(jù)編碼標(biāo)記為_MBCS 或 UNICODE,將右式函數(shù)做相應(yīng)的擴(kuò)展處理。宏定義方法類似于SetWindowText。

    不止strxxx()函數(shù)族中有TCHAR宏定義,其它一些函數(shù)中也有。例如,_stprintf (取代sprintf()和swprintf()),和 _tfopen (取代fopen() 和 _wfopen())。MSDN的全部宏定義在"Generic-Text Routine Mappings"欄目下。

    String 和 TCHAR 類型定義

    Win32 API 文件中列出的函數(shù)名都是通用名(如"SetWindowText"),所有的字符串都按照TCHAR類型處理。(只有XP除外,XP只使用Unicode類型)。下面是MSDN給出的常用類型定義:

     

    類型

    MBCS 編碼中的意義

    Unicode 編碼中的意義

    WCHAR

    wchar_t

    wchar_t

    LPSTR

    zero-terminated string of char (char*)

    zero-terminated string of char (char*)

    LPCSTR

    constant zero-terminated string of char (constchar*)

    constant zero-terminated string of char (constchar*)

    LPWSTR

    zero-terminated Unicode string (wchar_t*)

    zero-terminated Unicode string (wchar_t*)

    LPCWSTR

    constant zero-terminated Unicode string (const wchar_t*)

    constant zero-terminated Unicode string (const wchar_t*)

    TCHAR

    char

    wchar_t

    LPTSTR

    zero-terminated string of TCHAR (TCHAR*)

    zero-terminated string of TCHAR (TCHAR*)

    LPCTSTR

    constant zero-terminated string of TCHAR (const TCHAR*)

    constant zero-terminated string of TCHAR (const TCHAR*)

    何時使用TCHAR 和Unicode

    可能會有疑問:“為什么要用Unicode?我一直用的都是普通字符串。”

    在三種情況下要用到Unicode:

    1. 程序只運(yùn)行于Windows NT。
    2. 處理的字符串長于MAX_PATH定義的字符數(shù)。
    3. 程序用于Windows XP中的新接口,那里沒有A/W版本之分。

    大部分Unicode API不可用于Windows 9x。所以如果程序要在Windows 9x上運(yùn)行的話,要強(qiáng)制使用MBCS API (微軟推出一個可運(yùn)行于Windows 9x的新庫,叫做Microsoft Layer for Unicode。但我沒有試用過,無法說明它的好壞)。相反,NT內(nèi)部全部使用Unicode編碼,使用Unicode API可以加速程序運(yùn)行。每當(dāng)將字符串處理為MBCS API時,操作系統(tǒng)都會將字符串轉(zhuǎn)換為Unicode并調(diào)用相應(yīng)的Unicode API 函數(shù)。對于返回的字符串,操作系統(tǒng)要做同樣的轉(zhuǎn)換。盡管這些轉(zhuǎn)換經(jīng)過了高度優(yōu)化,模塊盡可能地壓縮到最小,但畢竟會影響到程序的運(yùn)行速度。

    NT允許使用超長文件名(長于MAX_PATH 定義的260),但只限于Unicode API使用。Unicode API的另外一個優(yōu)點(diǎn)是程序能夠自動處理輸入的文字語言。用戶可以混合輸入英文,中文和日文作為文件名。不必使用其它代碼來處理,都按照Unicode編碼方式處理。

    最后,作為Windows 9x的結(jié)局,微軟似乎拋棄了MBCS API。例如,SetWindowTheme() 接口函數(shù)的二個參數(shù)只支持Unicode編碼。使用Unicode編碼省卻了MBCS與Unicode之間的轉(zhuǎn)換過程。

    如果程序中還沒有使用到Unicode編碼,要堅持使用TCHAR和相應(yīng)的宏。這樣不但可以長期保持程序中DBCS編碼的安全性,也利于將來擴(kuò)展使用到Unicode編碼。那時只要改變預(yù)處理中的設(shè)置即可!

    C++字符串完全指南(2) - 各種字符串類(一)
    翻譯:連波
    19/11/2002
    URL: http://www.zdnet.com.cn/developer/tech/story/0,2000081602,39098621,00.htm

    前言

    C語言的字符串容易出錯,難以管理,并且往往是黑客到處尋找的目標(biāo)。于是,出現(xiàn)了許多字符串包裝類。可惜,人們并不很清楚什么情況下該用哪個類,也不清楚如何將C語言字符串轉(zhuǎn)換到包裝類。

    本文涉及到Win32 API,MFC,STL,WTL和Visual C++運(yùn)行庫中使用到的所有的字符串類型。說明各個類的用法,如何構(gòu)造對象,如何進(jìn)行類轉(zhuǎn)換等等。Nish為本文提供了Visual C++ 7的managed string 類的用法。

    閱讀本文之前,應(yīng)完全理解本指南第一部分中闡述的字符類型和編碼。

    字符串類的首要原則:

    不要隨便使用類型強(qiáng)制轉(zhuǎn)換,除非轉(zhuǎn)換的類型是明確由文檔規(guī)定的。

    之所以撰寫字符串指南這二篇文章,是因為常有人問到如何將X類型的字符串轉(zhuǎn)換到Z類型。提問者使用了強(qiáng)制類型轉(zhuǎn)換(cast),但不知道為什么不能轉(zhuǎn)換成功。各種各樣的字符串類型,特別是BSTR,在任何場合都不是三言二語可以講清的。因此,我以為這些提問者是想讓強(qiáng)制類型轉(zhuǎn)換來處理一切。

    除非明確規(guī)定了轉(zhuǎn)換算子,不要將任何其它類型數(shù)據(jù)強(qiáng)制轉(zhuǎn)換為string。一個字符串不能用強(qiáng)制類型轉(zhuǎn)換到string類。例如:

    void SomeFunc ( LPCWSTR widestr );
    main()
    {
      SomeFunc ( (LPCWSTR) "C:\\foo.txt" );  // 錯!
    }
    
    

    這段代碼100%錯誤。它可以通過編譯,因為類型強(qiáng)制轉(zhuǎn)換超越了編譯器的類型檢驗。但是,能夠通過編譯,并不證明代碼是正確的。

    下面,我將指出什么時候用類型強(qiáng)制轉(zhuǎn)換是合理的。
    C語言字符串與類型定義

    如指南的第一部分所述,Windows API定義了TCHAR術(shù)語。它可用于MBCS或Unicode編碼字符,取決于預(yù)處理設(shè)置為_MBCS 或 _UNICODE標(biāo)記。關(guān)于TCHAR的詳細(xì)說明請閱指南的第一部分。為便于敘述,下面給出字符類型定義:

    Type

    Meaning

    WCHAR

    Unicode character (wchar_t)

    TCHAR

    MBCS or Unicode character, depending on preprocessor settings

    LPSTR

    string of char (char*)

    LPCSTR

    constant string of char (constchar*)

    LPWSTR

    string of WCHAR (WCHAR*)

    LPCWSTR

    constant string of WCHAR (const WCHAR*)

    LPTSTR

    string of TCHAR (TCHAR*)

    LPCTSTR

    constant string of TCHAR (const TCHAR*)

    另外還有一個字符類型OLECHAR。這是一種對象鏈接與嵌入的數(shù)據(jù)類型(比如嵌入Word文檔)。這個類型通常定義為wchar_t。如果將預(yù)處理設(shè)置定義為OLE2ANSI,OLECHAR將被定義為char類型。現(xiàn)在已經(jīng)不再定義OLE2ANSI(它只在MFC 3以前版本中使用),所以我將OLECHAR作為Unicode字符處理。

    下面是與OLECHAR相關(guān)的類型定義:

    Type

    Meaning

    OLECHAR

    Unicode character (wchar_t)

    LPOLESTR

    string of OLECHAR (OLECHAR*)

    LPCOLESTR

    constant string of OLECHAR (const OLECHAR*)

    還有以下二個宏讓相同的代碼能夠適用于MBCS和Unicode編碼:

    Type

    Meaning

    _T(x)

    Prepends L to the literal in Unicode builds.

    OLESTR(x)

    Prepends L to the literal to make it an LPCOLESTR.

    宏_T有幾種形式,功能都相同。如: -- TEXT, _TEXT, __TEXT, 和 __T這四種宏的功能相同。

    COM中的字符串 - BSTR VARIANT

    許多COM接口使用BSTR聲明字符串。BSTR有一些缺陷,所以我在這里讓它獨(dú)立成章。

    BSTR是Pascal類型字符串(字符串長度值顯式地與數(shù)據(jù)存放在一起)和C類型字符串(字符串長度必須通過尋找到結(jié)尾零字符來計算)的混合型字符串。BSTR屬于Unicode字符串,字符串中預(yù)置了字符串長度值,并且用一個零字符來結(jié)尾。下面是一個"Bob"的BSTR字符串:

    注意,字符串長度值是一個DWORD類型值,給出字符串的字節(jié)長度,但不包括結(jié)尾零。在上例,"Bob"含有3個Unicode字符(不計結(jié)尾零),6個字節(jié)長。因為明確給出了字符串長度,所以當(dāng)BSTR數(shù)據(jù)在不同的處理器和計算機(jī)之間傳送時,COM庫能夠知道應(yīng)該傳送的數(shù)據(jù)量。

    附帶說一下,BSTR可以包含任何數(shù)據(jù)塊,不單是字符。它甚至可以包容內(nèi)嵌零字符數(shù)據(jù)。這些不在本文討論范圍。

    C++中的BSTR變量其實就是指向字符串首字符的指針。BSTR是這樣定義的:

    typedef OLECHAR* BSTR;

    這個定義很糟糕,因為事實上BSTR與Unicode字符串不一樣。有了這個類型定義,就越過了類型檢查,可以混合使用LPOLESTR和BSTR。向一個需要LPCOLESTR (或 LPCWSTR)類型數(shù)據(jù)的函數(shù)傳遞BSTR數(shù)據(jù)是安全的,反之則不然。所以要清楚了解函數(shù)所需的字符串類型,并向函數(shù)傳遞正確類型的字符串。

    要知道為什么向一個需要BSTR類型數(shù)據(jù)的函數(shù)傳遞LPCWSTR類型數(shù)據(jù)是不安全的,就別忘了BSTR必須在字符串開頭的四個字節(jié)保留字符串長度值。但LPCWSTR字符串中沒有這個值。當(dāng)其它的處理過程(如Word)要尋找BSTR的長度值時就會找到一堆垃圾或堆棧中的其它數(shù)據(jù)或其它隨機(jī)數(shù)據(jù)。這就導(dǎo)致方法失效,當(dāng)長度值太大時將導(dǎo)致崩潰。

    許多應(yīng)用接口都使用BSTR,但都用到二個最重要的函數(shù)來構(gòu)造和析構(gòu)BSTR。就是SysAllocString()和SysFreeString()函數(shù)。SysAllocString()將Unicode字符串拷貝到BSTR,SysFreeString()釋放BSTR。示例如下:

    BSTR bstr = NULL;
    bstr = SysAllocString ( L"Hi Bob!" );
    if ( NULL == bstr )
        // 內(nèi)存溢出
       // 這里使用bstr
    SysFreeString ( bstr );
    
    

    當(dāng)然,各種BSTR包裝類都會小心地管理內(nèi)存。

    自動接口中的另一個數(shù)據(jù)類型是VARIANT。它用于在無類型語言,諸如JScript,VBScript,以及Visual Basic,之間傳遞數(shù)據(jù)。VARIANT可以包容許多不用類型的數(shù)據(jù),如long和IDispatch*。如果VARIANT包含一個字符串,這個字符串是BSTR類型。在下文的VARIANT包裝類中我還會談及更多的VARIANT。
    C++字符串完全指南(2) - 各種字符串類- CRT類
    翻譯:連波
    20/11/2002
    URL: http://www.zdnet.com.cn/developer/tech/story/0,2000081602,39098682,00.htm

    _bstr_t

    字符串包裝類

    我已經(jīng)說明了字符串的各種類型,現(xiàn)在討論包裝類。對于每個包裝類,我都會說明它的對象構(gòu)造過程和如何轉(zhuǎn)換成C類型字符串指針。應(yīng)用接口的調(diào)用,或構(gòu)造另一個不同類型的字符串類,大多都要用到C類型指針。本文不涉及類的其它操作,如排序和比較等。

    再強(qiáng)調(diào)一下,在完全了解轉(zhuǎn)換結(jié)果之前不要隨意使用強(qiáng)制類型轉(zhuǎn)換。

    CRT類

    _bstr_t

    _bstr_t 是BSTR的完全包裝類。實際上,它隱含了BSTR。它提供多種構(gòu)造函數(shù),能夠處理隱含的C類型字符串。但它本身卻不提供BSTR的處理機(jī)制,所以不能作為COM方法的輸出參數(shù)[out]。如果要用到BSTR* 類型數(shù)據(jù),用ATL的CComBSTR類更為方便。

    _bstr_t 數(shù)據(jù)可以傳遞給需要BSTR數(shù)據(jù)的函數(shù),但必須滿足以下三個條件:

    首先,_bstr_t 具有能夠轉(zhuǎn)換為wchar_t*類型數(shù)據(jù)的函數(shù)。

    其次,根據(jù)BSTR定義,使得wchar_t* 和BSTR對于編譯器來說是相同的。

    第三,_bstr_t內(nèi)部保留的指向內(nèi)存數(shù)據(jù)塊的指針 wchar_t* 要遵循BSTR格式。

    滿足這些條件,即使沒有相應(yīng)的BSTR轉(zhuǎn)換文檔,_bstr_t 也能正常工作。示例如下:

     // 構(gòu)造
    _bstr_t bs1 = "char string";        // 從LPCSTR構(gòu)造 
    _bstr_t bs2 = L"wide char string"; // 從LPCWSTR構(gòu)造
    _bstr_t bs3 = bs1;              // 拷貝另一個 _bstr_t
    _variant_t v = "Bob";
    _bstr_t bs4 = v;              // 從一個含有字符串的 _variant_t 構(gòu)造
    // 數(shù)據(jù)萃取
    LPCSTR psz1 = bs1;              // 自動轉(zhuǎn)換到MBCS字符串
    LPCSTR psz2 = (LPCSTR) bs1;     // cast OK, 同上
    LPCWSTR pwsz1 = bs1;            // 返回內(nèi)部的Unicode字符串
    LPCWSTR pwsz2 = (LPCWSTR) bs1;  // cast OK, 同上
    BSTR    bstr = bs1.copy();      // 拷貝bs1, 返回BSTR
    // ...
      SysFreeString ( bstr );
    

    注意,_bstr_t 也可以轉(zhuǎn)換為char* 和 wchar_t*。這是個設(shè)計問題。雖然char* 和 wchar_t*不是常量指針,但不能用于修改字符串,因為可能會打破內(nèi)部BSTR結(jié)構(gòu)。

    _variant_t
    _variant_t

    _variant_t 是VARIANT的完全包裝類。它提供多種構(gòu)造函數(shù)和數(shù)據(jù)轉(zhuǎn)換函數(shù)。本文僅討論與字符串有關(guān)的操作。

    // 構(gòu)造
    _variant_t v1 = "char string"; // 從LPCSTR 構(gòu)造
    _variant_t v2 = L"wide char string"; // 從LPCWSTR 構(gòu)造
    _bstr_t bs1 = "Bob";
    _variant_t v3 = bs1; // 拷貝一個 _bstr_t 對象
    // 數(shù)據(jù)萃取
    _bstr_t bs2 = v1; // 從VARIANT中提取BSTR
    _bstr_t bs3 = (_bstr_t) v1; // cast OK, 同上
    

    注意,_variant_t 方法在轉(zhuǎn)換失敗時會拋出異常,所以要準(zhǔn)備用catch 捕捉_com_error異常。

    另外要注意 _variant_t 不能直接轉(zhuǎn)換成MBCS字符串。要建立一個過渡的_bstr_t 變量,用其它提供轉(zhuǎn)換Unicode到MBCS的類函數(shù),或ATL轉(zhuǎn)換宏來轉(zhuǎn)換。

    與_bstr_t 不同,_variant_t 數(shù)據(jù)可以作為參數(shù)直接傳送給COM方法。_variant_t 繼承了VARIANT類型,所以在需要使用VARIANT的地方使用_variant_t 是C++語言規(guī)則允許的。
    C++字符串完全指南(2) - STL和ATL類
    翻譯:連波
    21/11/2002
    URL: http://www.zdnet.com.cn/developer/tech/story/0,2000081602,39098845,00.htm

    STL類

    STL類

    STL只有一個字符串類,即basic_string。basic_string管理一個零結(jié)尾的字符數(shù)組。字符類型由模板參數(shù)決定。通常,basic_string被處理為不透明對象。可以獲得一個只讀指針來訪問緩沖區(qū),但寫操作都是由basic_string的成員函數(shù)進(jìn)行的。

    basic_string預(yù)定義了二個特例:string,含有char類型字符;which,含有wchar_t類型字符。沒有內(nèi)建的TCHAR特例,可用下面的代碼實現(xiàn):

    // 特例化
    typedef basic_string tstring; // TCHAR字符串
    // 構(gòu)造
    string str = "char string"; // 從LPCSTR構(gòu)造
    wstring wstr = L"wide char string"; // 從LPCWSTR構(gòu)造
    tstring tstr = _T("TCHAR string"); // 從LPCTSTR構(gòu)造
    // 數(shù)據(jù)萃取
    LPCSTR psz = str.c_str(); // 指向str緩沖區(qū)的只讀指針
    LPCWSTR pwsz = wstr.c_str(); // 指向wstr緩沖區(qū)的只讀指針
    LPCTSTR ptsz = tstr.c_str(); // 指向tstr緩沖區(qū)的只讀指針
    
    

    與_bstr_t 不同,basic_string不能在字符集之間進(jìn)行轉(zhuǎn)換。但是如果一個構(gòu)造函數(shù)接受相應(yīng)的字符類型,可以將由c_str()返回的指針傳遞給這個構(gòu)造函數(shù)。例如:

    // 從basic_string構(gòu)造_bstr_t 
    _bstr_t bs1 = str.c_str();  // 從LPCSTR構(gòu)造 _bstr_t
    _bstr_t bs2 = wstr.c_str(); // 從LPCWSTR構(gòu)造 _bstr_t
    
    ATL類
    CComBSTR

    CComBSTR 是ATL的BSTR包裝類。某些情況下比_bstr_t 更有用。最主要的是,CComBSTR允許操作隱含BSTR。就是說,傳遞一個CComBSTR對象給COM方法時,CComBSTR對象會自動管理BSTR內(nèi)存。例如,要調(diào)用下面的接口函數(shù):

    // 簡單接口
    struct IStuff : public IUnknown
    {
      // 略去COM程序...
      STDMETHOD(SetText)(BSTR bsText);
      STDMETHOD(GetText)(BSTR* pbsText);
    };
    

    CComBSTR 有一個BSTR操作方法,能將BSTR直接傳遞給SetText()。還有一個引用操作(operator &)方法,返回BSTR*,將BSTR*傳遞給需要它的有關(guān)函數(shù)。

    CComBSTR bs1;
    CComBSTR bs2 = "new text";
    pStuff->GetText ( &bs1 );       // ok, 取得內(nèi)部BSTR地址
      pStuff->SetText ( bs2 );        // ok, 調(diào)用BSTR轉(zhuǎn)換
      pStuff->SetText ( (BSTR) bs2 ); // cast ok, 同上
    

    CComVariant
    CComBSTR有類似于 _bstr_t 的構(gòu)造函數(shù)。但沒有內(nèi)建MBCS字符串的轉(zhuǎn)換函數(shù)。可以調(diào)用ATL宏進(jìn)行轉(zhuǎn)換。

    // 構(gòu)造
    CComBSTR bs1 = "char string"; // 從LPCSTR構(gòu)造
    CComBSTR bs2 = L"wide char string"; // 從LPCWSTR構(gòu)造
    CComBSTR bs3 = bs1; // 拷貝CComBSTR
    CComBSTR bs4;
    bs4.LoadString ( IDS_SOME_STR ); // 從字符串表加載
    // 數(shù)據(jù)萃取
    BSTR bstr1 = bs1; // 返回內(nèi)部BSTR,但不可修改!
    BSTR bstr2 = (BSTR) bs1; // cast ok, 同上
    BSTR bstr3 = bs1.Copy(); // 拷貝bs1, 返回BSTR
    BSTR bstr4;
    bstr4 = bs1.Detach(); // bs1不再管理它的BSTR
    // ...
    SysFreeString ( bstr3 );
    SysFreeString ( bstr4 );
    
    

    上面的最后一個示例用到了Detach()方法。該方法調(diào)用后,CComBSTR對象就不再管理它的BSTR或其相應(yīng)內(nèi)存。所以bstr4就必須調(diào)用SysFreeString()。

    最后討論一下引用操作符(operator &)。它的超越使得有些STL集合(如list)不能直接使用CComBSTR。在集合上使用引用操作返回指向包容類的指針。但是在CComBSTR上使用引用操作,返回的是BSTR*,不是CComBSTR*。不過可以用ATL的CAdapt類來解決這個問題。例如,要建立一個CComBSTR的隊列,可以聲明為:

      std::list< CAdapt> bstr_list;

    CAdapt 提供集合所需的操作,是隱含于代碼的。這時使用bstr_list 就象在操作一個CComBSTR隊列。

    CComVariant

    CComVariant 是VARIANT的包裝類。但與 _variant_t 不同,它的VARIANT不是隱含的,可以直接操作類里的VARIANT成員。CComVariant 提供多種構(gòu)造函數(shù)和多類型操作。這里只介紹與字符串有關(guān)的操作。

    // 構(gòu)造
    CComVariant v1 = "char string";       // 從LPCSTR構(gòu)造
    CComVariant v2 = L"wide char string"; // 從LPCWSTR構(gòu)造
    CComBSTR bs1 = "BSTR bob";
    CComVariant v3 = (BSTR) bs1;          // 從BSTR拷貝
    // 數(shù)據(jù)萃取
    CComBSTR bs2 = v1.bstrVal;            // 從VARIANT提取BSTR
    

    跟_variant_t 不同,CComVariant沒有不同VARIANT類型之間的轉(zhuǎn)換操作。必須直接操作VARIANT成員,并確定該VARIANT的類型無誤。調(diào)用ChangeType()方法可將CComVariant數(shù)據(jù)轉(zhuǎn)換為BSTR。

    CComVariant v4 = ... // 從某種類型初始化 v4
    CComBSTR bs3;
    if ( SUCCEEDED( v4.ChangeType ( VT_BSTR ) ))
        bs3 = v4.bstrVal;
    

    跟 _variant_t 一樣,CComVariant不能直接轉(zhuǎn)換為MBCS字符串。要建立一個過渡的_bstr_t 變量,用其它提供轉(zhuǎn)換Unicode到MBCS的類函數(shù),或ATL轉(zhuǎn)換宏來轉(zhuǎn)換。

    ATL轉(zhuǎn)換宏

    ATL轉(zhuǎn)換宏

    ATL的字符串轉(zhuǎn)換宏可以方便地轉(zhuǎn)換不同編碼的字符,用在函數(shù)中很有效。宏按照[source type]2[new type] 或 [source type]2C[new type]格式命名。后者轉(zhuǎn)換為一個常量指針 (名字內(nèi)含"C")。類型縮寫如下:


     A:MBCS字符串,char* (A for ANSI)
     W:Unicode字符串,wchar_t* (W for wide)
     T:TCHAR字符串,TCHAR*
     OLE:OLECHAR字符串,OLECHAR* (實際等于W)
     BSTR:BSTR (只用于目的類型)

    例如,W2A() 將Unicode字符串轉(zhuǎn)換為MBCS字符串,T2CW()將TCHAR字符串轉(zhuǎn)換為Unicode字符串常量。

    要使用宏轉(zhuǎn)換,程序中要包含atlconv.h頭文件。可以在非ATL程序中使用宏轉(zhuǎn)換,因為頭文件不依賴其它的ATL,也不需要 _Module全局變量。如在函數(shù)中使用轉(zhuǎn)換宏,在函數(shù)起始處先寫上USES_CONVERSION宏。它表明某些局部變量由宏控制使用。

    轉(zhuǎn)換得到的結(jié)果字符串,只要不是BSTR,都存儲在堆棧中。如果要在函數(shù)外使用這些字符串,就要將這些字符串拷貝到其它的字符串類。如果結(jié)果是BSTR,內(nèi)存不會自動釋放,因此必須將返回值分配給一個BSTR變量或BSTR的包裝類,以避免內(nèi)存泄露。

    下面是若干宏轉(zhuǎn)換示例:

    // 帶有字符串的函數(shù):
    void Foo ( LPCWSTR wstr );
    void Bar ( BSTR bstr );
    // 返回字符串的函數(shù):
    void Baz ( BSTR* pbstr );
    #include 
    main()
    {
    using std::string;
    USES_CONVERSION;    // 聲明局部變量由宏控制使用
    // 示例1:送一個MBCS字符串到Foo()
    LPCSTR psz1 = "Bob";
    string str1 = "Bob";
    Foo ( A2CW(psz1) );
      Foo ( A2CW(str1.c_str()) );
    // 示例2:將MBCS字符串和Unicode字符串送到Bar()
    LPCSTR psz2 = "Bob";
    LPCWSTR wsz = L"Bob";
    BSTR bs1;
    CComBSTR bs2;
    bs1 = A2BSTR(psz2);         // 創(chuàng)建 BSTR
      bs2.Attach ( W2BSTR(wsz) ); // 同上,分配到CComBSTR
    Bar ( bs1 );
      Bar ( bs2 );
    SysFreeString ( bs1 );      // 釋放bs1
      // 不必釋放bs2,由CComBSTR釋放。
    // 示例3:轉(zhuǎn)換由Baz()返回的BSTR
    BSTR bs3 = NULL;
    string str2;
    Baz ( &bs3 );          // Baz() 填充bs3內(nèi)容
    str2 = W2CA(bs3);      // 轉(zhuǎn)換為MBCS字符串
      SysFreeString ( bs3 ); // 釋放bs3
    }
    
    

    可以看到,向一個需要某種類型參數(shù)的函數(shù)傳遞另一種類型的參數(shù),用宏轉(zhuǎn)換是非常方便的。
    C++字符串完全指南(2) - MFC類
    翻譯:連波
    22/11/2002
    URL: http://www.zdnet.com.cn/developer/tech/story/0,2000081602,39098983,00.htm

    MFC類

    MFC類

    CString

    MFC的CString含有TCHAR,它的實際字符類型取決于預(yù)處理標(biāo)記的設(shè)置。通常,CString象STL字符串一樣是不透明對象,只能用CString的方法來修改。CString比STL字符串更優(yōu)越的是它的構(gòu)造函數(shù)接受MBCS和Unicode字符串。并且可以轉(zhuǎn)換為LPCTSTR,因此可以向接受LPCTSTR的函數(shù)直接傳遞CString對象,不必調(diào)用c_str()方法。

    // 構(gòu)造
    CString s1 = "char string"; // 從LPCSTR構(gòu)造
    CString s2 = L"wide char string"; // 從LPCWSTR構(gòu)造
    CString s3 ( ' ', 100 ); // 預(yù)分配100字節(jié),填充空格
    CString s4 = "New window text";
    // 可以在LPCTSTR處使用CString:
    SetWindowText ( hwndSomeWindow, s4 );
    // 或者,顯式地做強(qiáng)制類型轉(zhuǎn)換:
    SetWindowText ( hwndSomeWindow, (LPCTSTR) s4 );
    
    

    也可以從字符串表加載字符串。CString通過LoadString()來構(gòu)造對象。用Format()方法可有選擇地從字符串表讀取一定格式的字符串。

    // 從字符串表構(gòu)造/加載
    CString s5 ( (LPCTSTR) IDS_SOME_STR );  // 從字符串表加載
    CString s6, s7;
    // 從字符串表加載
      s6.LoadString ( IDS_SOME_STR );
    // 從字符串表加載打印格式的字符串
      s7.Format ( IDS_SOME_FORMAT, "bob", nSomeStuff, ... );
    

    第一個構(gòu)造函數(shù)看上去有點(diǎn)怪,但它的確是文檔標(biāo)定的字符串加載方式。

    注意,CString只允許一種強(qiáng)制類型轉(zhuǎn)換,即強(qiáng)制轉(zhuǎn)換為LPCTSTR。強(qiáng)制轉(zhuǎn)換為LPTSTR (非常量指針)是錯誤的。按照老習(xí)慣,將CString強(qiáng)制轉(zhuǎn)換為LPTSTR只能傷害自己。有時在程序中沒有發(fā)現(xiàn)出錯,那只是碰巧。轉(zhuǎn)換到非常量指針的正確方法是調(diào)用GetBuffer()方法。

    下面以往隊列加入元素為例說明如何正確地使用CString:

    CString str = _T("new text");
    LVITEM item = {0};
    item.mask = LVIF_TEXT;
      item.iItem = 1;
      item.pszText = (LPTSTR)(LPCTSTR) str; // 錯!
      item.pszText = str.GetBuffer(0);      // 正確
    ListView_SetItem ( &item );
      str.ReleaseBuffer();  // 將隊列返回給str
    

    pszText成員是LPTSTR,一個非常量指針,因此要用str的GetBuffer()。GetBuffer()的參數(shù)是CString分配的最小緩沖區(qū)。如果要分配一個1K的TCHAR,調(diào)用GetBuffer(1024)。參數(shù)為0,只返回指向字符串的指針。

    上面示例的出錯語句可以通過編譯,甚至可以正常工作,如果恰好就是這個類型。但這不證明語法正確。進(jìn)行非常量的強(qiáng)制類型轉(zhuǎn)換,打破了面向?qū)ο蟮姆庋b原則,并逾越了CString的內(nèi)部操作。如果你習(xí)慣進(jìn)行這樣的強(qiáng)制類型轉(zhuǎn)換,終會遇到出錯,可你未必知道錯在何處,因為你到處都在做這樣的轉(zhuǎn)換,而代碼也都能運(yùn)行。

    知道為什么人們總在抱怨有缺陷的軟件嗎?不正確的代碼就臭蟲的滋生地。然道你愿意編寫明知有錯的代碼讓臭蟲有機(jī)可乘?還是花些時間學(xué)習(xí)CString的正確用法讓你的代碼能夠100%的正確吧。

    CString還有二個函數(shù)能夠從CString中得到BSTR,并在必要時轉(zhuǎn)換成Unicode。那就是AllocSysString()和SetSysString()。除了SetSysString()使用BSTR*參數(shù)外,二者一樣。

    // 轉(zhuǎn)換成BSTR
    CString s5 = "Bob!";
    BSTR bs1 = NULL, bs2 = NULL;
    bs1 = s5.AllocSysString();
      s5.SetSysString ( &bs2 );
    // ...
      SysFreeString ( bs1 );
      SysFreeString ( bs2 );
    

    COleVariant 與CComVariant 非常相似。COleVariant 繼承于VARIANT,可以傳遞給需要VARIANT的函數(shù)。但又與CComVariant 不同,COleVariant 只有一個LPCTSTR的構(gòu)造函數(shù),不提供單獨(dú)的LPCSTR和LPCWSTR的構(gòu)造函數(shù)。在大多情況下,沒有問題,因為總是愿意把字符串處理為LPCTSTR。但你必須知道這點(diǎn)。COleVariant 也有接受CString的構(gòu)造函數(shù)。

    // 構(gòu)造
    CString s1 = _T("tchar string");
    COleVariant v1 = _T("Bob"); // 從LPCTSTR構(gòu)造
    COleVariant v2 = s1; // 從CString拷貝
    

    對于CComVariant,必須直接處理VARIANT成員,用ChangeType()方法在必要時將其轉(zhuǎn)換為字符串。但是,COleVariant::ChangeType() 在轉(zhuǎn)換失敗時會拋出異常,而不是返回HRESULT的出錯碼。

    // 數(shù)據(jù)萃取
    COleVariant v3 = ...; // 從某種類型構(gòu)造v3
    BSTR bs = NULL;
    try
        {
        v3.ChangeType ( VT_BSTR );
        bs = v3.bstrVal;
        }
      catch ( COleException* e )
        {
        // 出錯,無法轉(zhuǎn)換
        }
    SysFreeString ( bs );
    

    WTL類

    WTL類

    CString

    WTL的CString與MFC的CString的行為完全相同,參閱上面關(guān)于MFC CString的說明即可。

    CLR 及 VC 7 類

    System::String 是.NET的字符串類。在其內(nèi)部,String對象是一個不變的字符序列。任何操作String對象的String方法都返回一個新的String對象,因為原有的String對象要保持不變。String類有一個特性,當(dāng)多個String都指向同一組字符集時,它們其實是指向同一個對象。Managed Extensions C++ 的字符串有一個新的前綴S,用來表明是一個managed string字符串。

    // 構(gòu)造
    String* ms = S"This is a nice managed string";
    

    可以用unmanaged string字符串來構(gòu)造String對象,但不如用managed string構(gòu)造String對象有效。原因是所有相同的具有S前綴的字符串都指向同一個對象,而unmanaged string沒有這個特點(diǎn)。下面的例子可以說明得更清楚些:

    String* ms1 = S"this is nice";
    String* ms2 = S"this is nice";
    String* ms3 = L"this is nice";
    Console::WriteLine ( ms1 == ms2 ); // 輸出true
    Console::WriteLine ( ms1 == ms3);  // 輸出false
    

    要與沒有S前綴的字符串做比較,用String::CompareTo()方法來實現(xiàn),如:

      Console::WriteLine ( ms1->CompareTo(ms2) );
      Console::WriteLine ( ms1->CompareTo(ms3) );
    

    二者都輸出0,說明字符串相等。

    在String和MFC 7的CString之間轉(zhuǎn)換很容易。CString可以轉(zhuǎn)換為LPCTSTR,String有接受char* 和 wchar_t* 的二種構(gòu)造函數(shù)。因此可以直接把CString傳遞給String的構(gòu)造函數(shù):

      CString s1 ( "hello world" );
      String* s2 ( s1 );  // 從CString拷貝
    

    反向轉(zhuǎn)換的方法也類似:

      String* s1 = S"Three cats";
      CString s2 ( s1 );
    

    可能有點(diǎn)迷惑。從VS.NET開始,CString有一個接受String對象的構(gòu)造函數(shù),所以是正確的。

      CStringT ( System::String* pString );

    為了加速操作,有時可以用基礎(chǔ)字符串(underlying string):

    String* s1 = S"Three cats";
    Console::WriteLine ( s1 );
    const __wchar_t __pin* pstr = PtrToStringChars(s1);
    for ( int i = 0; i < wcslen(pstr); i++ )
        (*const_cast<__wchar_t*>(pstr+i))++;
    Console::WriteLine ( s1 );
    

    PtrToStringChars() 返回指向基礎(chǔ)字符串的 const __wchar_t* 指針,可以防止在操作字符串時,垃圾收集器去除該字符串。
    C++字符串完全指南(2) - 總結(jié)
    翻譯:連波
    23/11/2002
    URL: http://www.zdnet.com.cn/developer/tech/story/0,2000081602,39099061,00.htm

    字符串類的打印格式函數(shù)

    對字符串包裝類使用printf()或其它類似功能的函數(shù)時要特別小心。包括sprintf()函數(shù)及其變種,以及TRACE 和ATLTRACE 宏。它們的參數(shù)都不做類型檢驗,一定要給它們傳遞C語言字符串,而不是整個string對象。

    例如,要向ATLTRACE()傳遞一個_bstr_t 里的字符串,必須顯式用(LPCSTR)或 (LPCWSTR)進(jìn)行強(qiáng)制類型轉(zhuǎn)換:


      _bstr_t bs = L"Bob!";
      ATLTRACE("The string is: %s in line %d\n", (LPCSTR) bs, nLine);
    

    如果忘了用強(qiáng)制類型轉(zhuǎn)換,直接把整個 _bstr_t 對象傳遞給ATLTRACE,跟蹤消息將輸出無意義的東西,因為_bstr_t 變量內(nèi)的所有數(shù)據(jù)都進(jìn)棧了。

    所有類的總結(jié)

    常用的字符串類之間的轉(zhuǎn)換方法是:將源字符串轉(zhuǎn)換為C類型字符串指針,然后將該指針傳遞給目標(biāo)類的構(gòu)造函數(shù)。下面列出將字符串轉(zhuǎn)換為C類型指針的方法,以及哪些類的構(gòu)造函數(shù)接受C類型指針。

    Class

    string
    type

    convert to char*?

    convert to constchar*?

    convert to wchar_t*?

    convert to const wchar_t*?

    convert to BSTR?

    construct from char*?

    construct from wchar_t*?

    _bstr_t

    BSTR

    yes, cast1

    yes, cast

    yes, cast1

    yes, cast

    yes2

    yes

    yes

    _variant_t

    BSTR

    no

    no

    no

    cast to
    _bstr_t3

    cast to
    _bstr_t3

    yes

    yes

    string

    MBCS

    no

    yes, c_str()
    method

    no

    no

    no

    yes

    no

    wstring

    Unicode

    no

    no

    no

    yes, c_str()
    method

    no

    no

    yes

    CComBSTR

    BSTR

    no

    no

    no

    yes, cast
    to BSTR

    yes, cast

    yes

    yes

    CComVariant

    BSTR

    no

    no

    no

    yes4

    yes4

    yes

    yes

    CString

    TCHAR

    no6

    in MBCS
    builds, cast

    no6

    in Unicode
    builds, cast

    no5

    yes

    yes

    COleVariant

    BSTR

    no

    no

    no

    yes4

    yes4

    in MBCS builds

    in Unicode builds

    附注:

    1. 雖然 _bstr_t 可以轉(zhuǎn)換為非常量指針,但對內(nèi)部緩沖區(qū)的修改可能導(dǎo)致內(nèi)存溢出,或在釋放BSTR時導(dǎo)致內(nèi)存泄露。
    2. bstr_t 的BSTR內(nèi)含 wchar_t* 變量,所以可將const wchar_t* 轉(zhuǎn)換到BSTR。但這個用法將來可能會改變,使用時要小心。
    3. 如果轉(zhuǎn)換到BSTR失敗,將拋出異常。
    4. 用ChangeType()處理VARIANT的bstrVal。在MFC,轉(zhuǎn)換失敗將拋出異常。
    5. 雖然沒有BSTR的轉(zhuǎn)換函數(shù),但AllocSysString()可返回一個新的BSTR。
    6. 用GetBuffer()方法可臨時得到一個非常量TCHAR指針。
    posted @ 2006-03-09 16:52 小鐵匠 閱讀(27913) | 評論 (3)編輯 收藏
    http://dev.csdn.net/article/82070.shtm
    http://blog.csdn.net/lxblg/archive/2004/09/14/104207.aspx
    posted @ 2006-03-09 15:08 小鐵匠 閱讀(408) | 評論 (0)編輯 收藏
         摘要: Iptables 指南 1.1.19 Oskar Andreasson      oan@frozentux.net     Copyright ? 2001-2003 by Oskar Andreasson 本文在符合 GNU Free Documentation 許可版本1.1的...  閱讀全文
    posted @ 2006-03-09 15:07 小鐵匠 閱讀(826) | 評論 (0)編輯 收藏
      2006年3月8日

    啟動server時如果遇到找不到stub問題,原因是rmiregistry找不到stub,而不是java com.Server找不到stub,解決方法,在stub的類同一個目錄下啟動rmiregistry

    posted @ 2006-03-08 11:20 小鐵匠 閱讀(694) | 評論 (0)編輯 收藏
    僅列出標(biāo)題  下一頁
    主站蜘蛛池模板: 全黄A免费一级毛片| 麻豆69堂免费视频| 国产免费卡一卡三卡乱码| 免费无码又爽又黄又刺激网站| 亚洲欧洲精品成人久久曰| 亚洲欧洲中文日韩久久AV乱码| 久艹视频在线免费观看| 亚洲久悠悠色悠在线播放| 久久久亚洲精品蜜桃臀| 成人最新午夜免费视频| 一级人做人a爰免费视频| 亚洲综合色丁香麻豆| 亚洲国产午夜中文字幕精品黄网站| 免费中文字幕一级毛片| 噼里啪啦免费观看高清动漫4| 2022国内精品免费福利视频| 亚洲一区二区三区高清在线观看| 亚洲福利在线观看| 亚洲福利精品电影在线观看| aa级一级天堂片免费观看| 久久精品视频免费播放| 中文字幕亚洲免费无线观看日本| 免费看又黄又爽又猛的视频软件| 人体大胆做受免费视频| 亚洲中文字幕无码mv| 国产成人亚洲精品91专区高清 | 最近中文字幕无吗高清免费视频| 永久免费毛片手机版在线看| 免费A级毛片在线播放| 国产精品无码永久免费888| 污污网站18禁在线永久免费观看| 一个人看的www免费视频在线观看 一个人免费视频观看在线www | 特级做A爰片毛片免费69| 国产无遮挡裸体免费视频 | 午夜免费啪视频在线观看| 18禁止看的免费污网站| 久久精品免费观看| 一个人免费观看视频www| 国产午夜鲁丝片AV无码免费| 亚洲女初尝黑人巨高清| 亚洲国产中文字幕在线观看|