franksunny的个人技术空间
获得人生中的成功需要的专注与坚持不懈多过天才与机会。 ——C.W. Wendte

 

描述符<>转换

 

业余有时候把一个事情当作任务来做的时候,往往会很受限制,就象这篇文档,上次写了个上篇,关于描述符的下篇,自己就迟迟没有勇气和时间写完,好几次都想静下心来好好完成它,但是都未能如愿,可如果不写显然我也不好意思写其它的一些东西,闲话提到这里,花了几天业余时间总算是完成了,该文质量不足之处还望读者您见谅。

 

通过前面关于描述符概念和使用的简单描述,下面我们直接进入描述符转换的主题。

虽然描述符有五类,但是作为描述符变量用的,只有三类即栈描述符、堆描述符、指针描述符。所以本文所述描述符的转换也只是在这三种类型间展开,这三类描述符之间的互相转换其实可以用下面这种伪代码方式给出:

TBuf<20> iBuf;

TPtr iPtr((const_cast<TUint16*>(iBuf.Ptr())),iBuf.Length(), iBuf.Length());

HBufC     *iHbuf;

iBuf = iPtr;

iBuf = iHbuf->Des();

iPtr.Set((const_cast<TUint16*>(iBuf.Ptr())),iBuf.Length(), iBuf.Length());

由上面可知指针型可以起堆型和栈型描述符的中间过渡的桥梁作用。

 

不可修改向可修改描述符的转换

原则1:通过不可修改描述符类内的Des()函数,将不可修改的描述符转换成可修改的指针描述符

示例1TBufC转换成TPtr

       _LIT(KText, "Test Data");

       TBufC<10> NBuf ( KText );

       TPtr     Pointer = NBuf.Des();

示例2HBufC转换成TPtr

HBufC * Buf = HBufC::NewL(15);

       _LIT (KText , "Test Text");

       *Buf = KText;

       TPtr Pointer = Buf->Des();

 

原则2:通过TPtr的构造函数或Set()函数可以将TPtrC描述转换为可修改的指针描述符

示例3TPtrCTPtr

const TText * text1 = _S("Hello World\n");

TPtrC Ptr1(text1);

TPtrC Ptr2(Ptr1);

//可以通过构造函数

TPtr Ptr3((TUint16 *)(Ptr1.Ptr()), Ptr1.Length());

//也可以通过Set()函数

Ptr3.Set((TUint16 *)(Ptr1.Ptr()),Ptr1.Length(), Ptr1.Length());

 

8位和16位之间的描述符转换

8位到16位的描述符转换

原则1:通过将两个8位描述符的内容合并为一个16位描述符的方法实现内存不动,内存块类型强转(我称其为保留描述符字节大小方法)。

示例48bit To 16bit保留描述符字节大小方法1

_LIT8(KText , "Test Text");

TBuf8<20> iBuf8(KText);//描述符实际占用了9个字节98位描述符

TBuf<20> iBuf16;

//实现内存块的强转

TPtrC16 ptr16(reinterpret_cast<const TUint16*>(iBuf8.Ptr()), (iBuf8.Length()/2));

//真实的内存不动已经结束,这里是重新申请了一块内存并实现内存赋值拷贝

iBuf16 = ptr16;//描述符实际占用了8个字节416位描述符,导致数据丢失

由上面的这个例子明显是丢失了数据了,原因就出在设置长度时用了(iBuf8.Length()/2),为了剔除错误,我后来改了一个新的示例6

示例68bit To 16bit保留描述符字节大小方法2(由于上例用了TPtrC,所以该例使用TPtr指针,以扩展应用)

_LIT8(KText , "Test Text");

TBuf8<20> iBuf8;

iBuf8.FillZ(20);

iBuf8 = KText;//实际占用9字节9描述符

TBuf<20> iBuf16;

TPtr ptr16(reinterpret_cast<TUint16*>(const_cast<TUint8*>(iBuf8.Ptr())),
   ((iBuf8.Length()+1)/2),((iBuf8.Length()+1)/2));

iBuf16 = ptr16;//实际占用10字节5描述符,但是第10个字节为0零值,也即9字节大小有用

注:其实这里用堆描述符来说明可能更好些,但是本人在调试过程中为了能够看到调试的效果,所以用了TBuf;而且个人觉得通常这种方法主要在文件读取等实际过程中用到,如果要转换为16位的话,肯定是偶数大小的8位描述符。

 

原则2:重新构建内存块使用描述符的copy函数将8位字符的高字节置为0低字节不变,进行拷贝转换(我称其为保留描述符长度方法)。

示例7

_LIT8(KText , "Test Text");

TBuf8<20> iBuf8(KText);//实际占用了9个描述符9个字节

TBuf<20> iBuf16;

iBuf16.Copy(iBuf8);//实际占用了9个描述符18个字节

 

原则3:使用charconv.lib内的API函数8位的UTF8描述符转换为16位的Unicode 描述符

CnvUtfConverter::ConvertToUnicodeFromUtf8(iBuf, iBuf8);

注:在使用这种方法时除了包含charconv.lib库,还应该包含utf.h头文件

 

原则4:使用GBKUnicode的方法

注:原则34是我在实际中常用的方法,涉及到各种编码的问题,暂时不做大的展开,下次使用中文的整理时再展开。

 

16位到8位的描述符转换

原则1:通过将一个16位描述符拆分为两个8位描述符的方法实现内存不动,内存块类型强转(我称其为保留描述符字节大小方法)

示例8

_LIT(KText , "Test 文本");

TBuf<20> iBuf(KText);//描述符实际占用了14个字节716位描述符                            //实现内存块的强转

TPtrC8 ptr8(reinterpret_cast<const TUint8*>(iBuf.Ptr()), (iBuf.Size()));

//真实的内存不动已经结束,这里是重新申请了一块内存并实现内存赋值拷贝

TBuf8<20> iBuf8;

iBuf8 = ptr8;//描述符实际占用了14个字节148位描述符

以上

原则2:重新构建内存块使用描述符的copy函数将16位描述符的,进行拷贝转换(我称其为保留描述符长度方法)。

示例9

_LIT(KText , "Test 文本");

TBuf<20> iBuf(KText);// 描述符实际占用了14个字节716位描述符

TBuf8<20> iBuf8;

iBuf8.Copy(iBuf);//描述符实际占用了7个字节7个描述符,非ASCII字符值转为1

注:该种方法在纯ASCII码的转换时可行,其它数据大于255的时候就会丢失数据。

 

原则3:使用charconv.lib内的API函数16位的Unicode描述符转换为8位的UTF8描述符。

CnvUtfConverter::ConvertFromUnicodeToUtf8(iBuf8, iBuf);

 

原则4:使用UnicodeGBK的方法

同前面理,以后我会再讲到。

 

由于最近做通信模块时组解包用的比较多,为此经常会将memcpystrcpysprintfsscanf等函数在char字符串和描述符串内存块之间的直接使用,个人觉得描述符一旦取得了后面数据区的首指针,那么内存块的这些操作没有什么好展开,直接用函数大家都会,当然本人也推荐读者使用文后的char字符串和Symbian描述符串的转换方法。

 

在整理过程种,也有其它类型与描述符的转换,我就摘录在本文后面作为mark和备查:

1.    TTimeTBuf

TBuf<32> theTime;//存储转换后的时间

TTime tt;

tt.HomeTime();

_LIT(KTimeFormat,"%Y%M%D%1-%2-%3 %H:%T:%S");//格式为:2006-03-04 12:12:12

tt.FormatL(theTime,KTimeFormat);

 

2.    TDateTimeTBuf

TTime currentTime;//声明一个TTime类型

currentTime.HomeTime();//设置TTime为当前时间

TDateTime tdt=currentTime.DateTime();//TTime  --->  TdateTime

TBuf<32> tmp;//存储转换完的Buf

tmp.AppendNum(tdt.Year());//AppendNum()方法将一个Tint加入到TBuf中。

_LIT(gang,"-");//声明一个横线分隔年月日,同样可声明冒号分隔小时分秒

tmp.Append(gang);

tmp.AppendNum(tdt.Month());

tmp.Append(gang);

tmp.AppendNum(tdt.Day());//…………时分秒的转换同上

 

3.    TBufTint互转型

// 15位数字

TInt iNum1(123456789009876);

// TIntTBuf

iBuf.Num(iNum1);//buf只用来转Tint可以使用AppendNum,但是性质是不一样的

 

// 使用iBuf包含的内容创建TLex对象

TLex iLex(iBuf);

TInt iNum2;

//TBufTInt

iLex.Val(iNum2);// Num2现在包含了15位数字

 

4.    TBufTDateTime

将长的TBuf截成小段,分别是年月日时分秒,通过下面TBufTInt ,再分别把转换成TInt的年月日取出,通过TDateTimesetYear(),setMonth()等方法将时间setTdateTime

 

5. .symbian串转换成char

char* p = NULL;

TBuf8<20> buf( _L( "aaaaa" ) );

p = (char *)buf.Ptr();

 

6.char串转换成symbian

char* cc = "aaaa";

TPtrC8 a;

a.Set( (const TUint8*)cc , strlen(cc) );

 

本文参考了一些论坛资料,至于资料索引,我也无法给出,望读者见谅,有错误之处还望指出。

posted on 2007-11-28 22:51 frank.sunny 阅读(4916) 评论(15)  编辑 收藏 引用 所属分类: symbian 开发

FeedBack:
# re: 描述符转换
2007-11-29 22:25 | helixapp
真的挺全的 赞一个  回复  更多评论
  
# re: 描述符转换
2008-03-03 15:37 | myh
博主的示例6:8bit To 16bit保留描述符字节大小方法2(由于上例用了TPtrC,所以该例使用TPtr指针,以扩展应用)


_LIT8(KText , "Test Text");

TBuf8<20> iBuf8;

iBuf8.FillZ(20);

iBuf8 = KText;//实际占用9字节9描述符

TBuf<20> iBuf16;

TPtr ptr16(reinterpret_cast<TUint16*>(const_cast<TUint8*>(iBuf8.Ptr())),
((iBuf8.Length()+1)/2),((iBuf8.Length()+1)/2));

iBuf16 = ptr16;//

// 本人在Draw函数中引用了你上面的代码,,同时调用下面语句
gc.DrawText(iBuf16,TPoint(0,20));
在模拟器上显示的是乱码,,不知为什么,,
  回复  更多评论
  
# re: 描述符转换
2008-03-04 10:50 | frank.sunny
@myh
好久没来更新了,今天在邮箱里看到来自博客园的邮件感觉好亲切

谢谢myh兄,还自己去做过实验,其实8位到16位的前两个原则只是保证在内存块中数据一致,不放你可以自己调试看看内存里面内容,但是你在显示的时候8位和16位的编码不一样自然就会出现乱码了

其实这个问题还是涉及编码的问题,由于后来项目紧就一直没有更新博客了,myh兄可以采用原则3和4,肯定不会出现乱码的,并且如果是中文,在模拟器上如果采用了中文SDK是不会出现乱码的,在手机上可能还会出现乱码,这个只能以后详细解说了

再次感谢myh兄参与讨论


  回复  更多评论
  
# re: 描述符转换
2008-03-20 11:26 | myh
多谢回复,,最近在学习真机上中文显示问题,,感觉比较复杂,,

用两种方法实现了真机上中文显示,,
1、CnvUtfConverter::ConvertToUnicodeFromUtf8(iBuf, iBuf8);

2、CCnvCharacterSetConverter中的ConvertToUnicode

但第一种方法存在文件保存时的格式问题,,选择UTF-8 无 BOM格式,,当文件中的内容改变时又会出问题,,
能不能把整个项目发到你的邮箱里,,帮我看一下,,

另外第二种方法比较耗时,,但比较方便,,  回复  更多评论
  
# re: 描述符转换
2008-03-20 11:58 | frank.sunny
阁下连耗时与否都做过比较了,非常感激,但是不知道具体是怎样耗时法,本人未做过这方面的实验。
照理转成utf8应该无问题啊,不知道怎么联系阁下,我的邮箱是:frank.sunny@163.com
  回复  更多评论
  
# re: 描述符转换
2008-03-20 12:03 | myh

第一种方法,,
_LIT8(KOpentoMap8, "返回我的最爱");
会报以下错
error C2001: 常数中有换行符
fatal error C1057: 宏展开中遇到意外的文件结束

但是将文字改成以下几种情况又不会报错
1、_LIT8(KOpeap8, "返回我的最");
2、_LIT8(KOpeap8, "城市设置成功");
3、_LIT8(KOpeap8, "返回我的最w");


  回复  更多评论
  
# re: 描述符转换
2008-03-20 12:12 | frank.sunny
不知道你是怎么考虑的,照理“_LIT8(KOpentoMap8, "返回我的最爱");”这个语句应该是“_LIT(KOpentoMap8, "返回我的最爱");”吧 ?

我不是很清楚你要实现什么目的


  回复  更多评论
  
# re: 描述符转换
2008-03-20 12:50 | myh
我定义了一个专门存放字符常量的头文件,,Common.h

其中有_LIT8(KOpentoMap8, "返回我的最爱");
ccp文件中调用
CnvUtfConverter::ConvertToUnicodeFromUtf8(iBuf, KOpentoMap8);


最后调用DrawText; 以显示中文,,“返回我的最爱”
  回复  更多评论
  
# re: 描述符转换
2008-03-20 13:27 | frank.sunny
不好意思,刚刚午睡下
你这样是不对的,“_LIT8(KOpentoMap8, "返回我的最爱");"中的"返回我的最爱"是GBK编码的,而_LIT8并非转化为utf-8的,仍然是GBK编码的。这个在symbian中现在一般不推荐使用,只针对ASCII码时是适用的。
关于GBK转化到Unicode另外有代码实现的,也怪自己偷懒老是没有整理这个东西,我有时间整理下吧。  回复  更多评论
  
# re: 描述符转换
2008-03-20 13:58 | myh
没事,,



_LIT8(KOpentoMap8, "返回我的最爱");"中的"返回我的最爱"是GBK编码的,

我已经将文件Commom.h头文件存为UTF-8 无 BOM 格式 了,,所以

返回我的最爱 应该是UTF-8 无 BOM 编码了,,  回复  更多评论
  
# re: 描述符转换
2008-03-20 14:28 | frank.sunny
不知道阁下如何联系,想问下无bom和有bom具体是什么关系啊
我不懂呢,查了下有bom多了内容为“FFFE”,对吧,但是有什么用,能告知下吗  回复  更多评论
  
# re: 描述符转换
2008-03-20 15:20 | myh
644621379

其实我也不太懂,,昨天看到的,,你加我吧,,咱们QQ聊,,  回复  更多评论
  
# re: 描述符转换
2008-06-25 19:42 | wangfsun
symbian学习中,借用了你的一些资料,很感谢  回复  更多评论
  
# re: 描述符转换
2008-11-28 09:36 | liuhz
很好得文章,非常感谢分享。再接再厉,呵呵。  回复  更多评论
  
# re: 描述符转换
2011-01-13 11:24 | longteng9
// 15位数字

TInt iNum1(123456789009876);

// TInt转TBuf

iBuf.Num(iNum1);//当buf只用来转Tint时可以使用AppendNum,但是性质是不一样的
我用写在文件中
TBuf8<20> buf=iBuf.Num(iNum1);
iFile.Write(buf);  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理



常用链接

留言簿(13)

随笔分类

个人其它博客

基础知识链接

最新评论

阅读排行榜

评论排行榜