
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年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:
-
程序只運(yùn)行于Windows NT。
- 處理的字符串長于MAX_PATH定義的字符數(shù)。
- 程序用于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_t 3 |
cast to
_bstr_t 3 |
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 |
附注:
-
雖然 _bstr_t 可以轉(zhuǎn)換為非常量指針,但對內(nèi)部緩沖區(qū)的修改可能導(dǎo)致內(nèi)存溢出,或在釋放BSTR時導(dǎo)致內(nèi)存泄露。
- bstr_t 的BSTR內(nèi)含 wchar_t* 變量,所以可將const wchar_t* 轉(zhuǎn)換到BSTR。但這個用法將來可能會改變,使用時要小心。
- 如果轉(zhuǎn)換到BSTR失敗,將拋出異常。
- 用ChangeType()處理VARIANT的bstrVal。在MFC,轉(zhuǎn)換失敗將拋出異常。
- 雖然沒有BSTR的轉(zhuǎn)換函數(shù),但AllocSysString()可返回一個新的BSTR。
- 用GetBuffer()方法可臨時得到一個非常量TCHAR指針。
posted @
2006-03-09 16:52 小鐵匠 閱讀(27913) |
評論 (3) |
編輯 收藏
http://dev.csdn.net/article/82070.shtmhttp://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) |
編輯 收藏