关于内存对齐以及通过偏移获得结构地址[转]

结构体的sizeof

这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:



struct S1

{

char c;

int i;

};

问sizeof(s1)等于多少?聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗?你在你机器上试过了吗?也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。

Why?为什么受伤的总是我?

请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:

S1 s1 = { a , 0xFFFFFFFF };

定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么?

以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:

0012FF78: 61 CC CC CC FF FF FF FF

发现了什么?怎么中间夹杂了3个字节的CC?看看MSDN上的说明:

When applied to a structure type or variable, sizeof returns the actual size,

which may include padding bytes inserted for alignment.

原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。

为什么需要字节对齐?计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。

让我们交换一下S1中char与int的位置:

struct S2

{

int i;

char c;

};

看看sizeof(S2)的结果为多少,怎么还是8?再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊?别着急,下面总结规律。

字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
对于上面的准则,有几点需要说明:

1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢?因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。

结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:

#define offsetof(s,m) (size_t)&(((s *)0)->m)

例如,想要获得S2中c的偏移量,方法为

size_t pos = offsetof(S2, c);// pos等于4
2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。

这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):

struct S3

{

char c1;

S1 s;

char c2

};

S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。

c1的偏移量为0,s的偏移量呢?这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。

通过上面的叙述,我们可以得到一个公式:

结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:



sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( trailing padding )

到这里,朋友们应该对结构体的sizeof有了一个全新的认识,但不要高兴得太早,有一个影响sizeof的重要参量还未被提及,那便是编译器的pack指令。它是用来调整结构体对齐方式的,不同编译器名称和用法略有不同,VC6中通过#pragma pack实现,也可以直接修改/Zp编译开关。#pragma pack的基本用法为:#pragma pack( n ),n为字节对齐数,其取值为1、2、4、8、16,默认是8,如果这个值比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,公式如下:

offsetof( item ) = min( n, sizeof( item ) )

再看示例:

#pragma pack(push) // 将当前pack设置压栈保存

#pragma pack(2)// 必须在结构体定义之前使用

struct S1

{

char c;

int i;

};

struct S3

{

char c1;

S1 s;

char c2

};

#pragma pack(pop) // 恢复先前的pack设置

计算sizeof(S1)时,min(2, sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)等于6,能够被2整除,所以整个S1的大小为6。

同样,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,加上sizeof(c2)等于9,不能被2整除,添加一个填充字节,所以sizeof(S3)等于10。

现在,朋友们可以轻松的出一口气了, 还有一点要注意,“空结构体”(不含数据成员)的大小不为0,而是1。试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢?于是,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。

如下:

struct S5 { };

sizeof( S5 ); // 结果为1



8. 含位域结构体的sizeof

前面已经说过,位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof,只是考虑到其特殊性而将其专门列了出来。

C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。

使用位域的主要目的是压缩存储,其大致规则为:

1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;

4) 如果位域字段之间穿插着非位域字段,则不进行压缩;

5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

还是让我们来看看例子。

示例1:

struct BF1

{

char f1 : 3;

char f2 : 4;

char f3 : 5;

};

其内存布局为:

|_f1__|__f2__|_|____f3___|____|

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|

0 3   7 8   1316

位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只能从下一个字节开始。因此sizeof(BF1)的结果为2。

示例2:

struct BF2

{

char f1 : 3;

short f2 : 4;

char f3 : 5;

};

由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。

示例3:

struct BF3

{

char f1 : 3;

char f2;

char f3 : 5;

};

非位域字段穿插在其中,不会产生压缩,在VC6和Dev-C++中得到的大小均为3。



9. 联合体的sizeof

结构体在内存组织上是顺序式的,联合体则是重叠式,各成员共享一段内存,所以整个联合体的sizeof也就是每个成员sizeof的最大值。结构体的成员也可以是复合类型,这里,复合类型成员是被作为整体考虑的。

所以,下面例子中,U的sizeof值等于sizeof(s)。

union U

{

int i;

char c;

S1 s;

};

Symbian获取系统时间并转换为描述符

TTime currentTime;

currentTime.HomeTime();

TBuf<100> time;

currentTime.FormatL(time,_L(“%Y_%M_%D_%H_%T_%S_%C”)); //___18_13_37_474750

LOG(time);

currentTime.FormatL(time,_L(“%Y %M %D %H%T%S%C”));    //    181337474750

LOG(time);

currentTime.FormatL(time,_L(“%Y%M%D%H%T%S%C”));       //181337474750

LOG(time);

currentTime.FormatL(time,_L(“%Y-%M-%D %H%T%S%C”));    //– 181337474750

LOG(time);

currentTime.FormatL(time,_L(“%H:%T:%S on %E, %F%D-%*M-%Y”));//18:13:37 on Monday, 13-8-2007

LOG(time);

currentTime.FormatL(time,_L(“%H:%T:%S on %E, %F%D-%M-%Y”));//18:13:37 on Monday, 13-08-2007

LOG(time);

currentTime.FormatL(time,_L(“%F %D %M %Y %H:%T”)); // 13 08 2007 18:13

LOG(time);

currentTime.FormatL(time,_L(“%-B%:0%J%:1%T%:2%S%:3″)); //18:13:37

LOG(time);

currentTime.FormatL(time,_L(“%Y%M%D%/0%1%/1%2%/2%3%/3″)); //2007/08/13

LOG(time);   

currentTime.FormatL(time,_L(“%H%T%S%C%F%D%M%Y”));//18133701234513082007

LOG(time);

currentTime.FormatL(time,_L(“%-B%:0%J%:1%T%:2%S%+B    %D %N %Y   %4 %5 %3″)); //7:36:35 pm        August 06 06

LOG(time);


示例:
TTime currentTime;

currentTime.HomeTime(); //将time设置为系统时间

TBuf<32> timeBuf;

currentTime.FormatL(timeBuf,_L(“%F%Y/%M/%D,%H:%T:%S”)); //将系统时间格式化为 2008/08/16,21:22:22 ,并存至timeBuf。




详解:

格式串分为本地相关和本地无关格式串,也就是说和系统的时间日期中设置的格式是否相关。

以下所有格式字符都要加%

本地无关:

%:因为%是参数字符,所以需要输出%的时候,要用两个连续的%%进行转义

*:加在%后,表示需要缩写,比如%*T表示对分钟进行缩写,如果不是两位数,则去掉前导0

C:6位的微秒,%C默认是6位的,%*C2表示只取前两位,%*C4则取前4位

S:2位的秒,加*去掉前导0

T:2位的分,加*去掉前导0

H:24小时制的时,加*去掉前导0

I:12小时制的时,加不加*都会去掉前导0

F:%F参数表示D/M/Y三个参数都是本地无关的,按照格式串原样输出,%F需要用在%D、%M、%Y之前

D:2位的日,加*去掉前导0

M:2位的月,加*去掉前导0

Y:4位的年,加*去掉前两个数字,比如2008只显示08

E:星期,英文环境下,Sunday~Saturday,加*显示缩写,Sun~Sat;中文环境下,星期一~星期日,加*显示缩写,一~日

N:月的名称,英文环境下,January~December,加*显示缩写,Jan~Dec;中文环境下,1月~12月,加*显示缩写,阿拉伯数字1~12。注意1月~12月数字都是阿拉伯数字,而不是汉字一~十二

W:2位数字,当前日期处于一年中的第几周,加*去掉前导0

X:日期后缀。例如%*D%X显示形如3rd(三号),%D%X显示形如02nd(二号)

Z:3位数字,当前日期处于一年中的第几天,加*去掉前导0

本地相关:

.:(点号)%.默认是小数点,表示分隔秒与毫秒之间的字符。可以通过TLocale::SetDecimalSeparator()设定。

::(冒号)%:表示获取本地设置中的时间分隔符,紧跟一个0~3范围的数字来指定哪一个日期分隔符。

格 式如下:S0 XX S1 YY S2 ZZ S3,其中XX、YY、ZZ代表时分秒,S0~S3代表4个分隔符。%:0表示第一个分隔符,依此类推。需要注意的是,本地设置中的时间分隔符只提供冒号和点号两种字符。当然,可以通过TLocale:: SetTimeSeparator()对4个分隔符进 行设置,模拟器和真机都未试验成功,待机状态的时间分隔符未更改。

/:(斜杠)%/表示获取本地设置中的日期分隔符,和上面一条类似。XX、 YY、ZZ代表年月日,其顺序可以通过TLocale:: SetDateFormat()设置。对于分隔符,本地设置中提供4种字符以供选择,不过只对 S1和S2有效,S0和S3总是空字符。通过SetDateSeparator()可以对4个分隔符S0~S3进行分别设定,且可以是不同的,在模拟器和真机上都试验成功,待机状态的日期分隔符被成功修改,但是进入系统的时间日期设定时,模拟器和真机均崩溃。

1:%1,本地设置中“年月日”顺序中的第一个。年月日顺序可以通过TLocale::SetDateFormat()进行设定,格式如下:

EDateAmerican US format (mm/dd/yyyy) 此时%1是月

EDateEuropean European format (dd/mm/yyyy) 此时%1是日

EDateJapanese Japanese format (yyyy/mm/dd) 此时%1是年

中国习惯上采用小日本格式

2:%2,本地设置中“年月日”顺序中的第二个。

3:%3,本地设置中“年月日”顺序中的第三个。

4:%4,和%2冗余,本地设置中是EDateAmerican的话,%4是日;EDateEuropean、EDateJapanese的%4是月

5:%5,和%3冗余,本地设置中是EDateAmerican、EDateEuropean的话,%4是年;EDateJapanese的%4是日

所以,在本地相关的格式串中(没有%F参数),调用年月日可以直接使用%1%2%3即可,无需加上%M%D%Y(一般在需要去掉前导0的时候才需要加上 %*M%*D%*Y),分隔符全部使用%/1即可(因为本地的设置中只有S1和S2有效,并且是相同的),当然年月日顺序是个问题,如果需要指定顺序,那肯定用%F的本地无关格式串了,那样简单直观地多,格式串也不容易写错。


A:不管本地设置中是12小时制还是24小时制,%A表示 am/pm总是显示。TLocale:: SetAmPmSpaceBetween()这个方法用来设置是否在时间和am/pm中间留有空格,显然这个设置会影响到最终格式化后的字符串。%*A会强制压缩这个空格,不管本地是否设置了空格(需要注意的是,这里提到的本地设置,不一定在系统的时间日期中有设置选项,因为对于用户而言,只需要设定常用的几个设置即可,比如这个AmPmSpaceBetween空格,在时间日期中就没有设置选项,系统默认是有空格的)。至于格式化后的字符串中am/pm出现在时间的前面还是后面,就要看格式串怎么写了:%I:%T:%S%A,显示10:21:36 pm,%A %I:%T:%S,显示pm 10:21:36

A的扩展选项:

在A前面可以加上+或者-,

%+A表示只有TLocale:: AmPmSymbolPosition()被设置为ELocaleAfter时,才往格式化后的字符串中插入am/pm;

%-A表示只有TLocale:: AmPmSymbolPosition()被设置为ELocaleBefore时,才往格式化后的字符串中插入am/pm。

很显然TLocale:: AmPmSymbolPosition()这个设置在时间日期设置中也是没有的。

eg:%-A%I:%T:%S%+A这个串格式化之后的字符串中am/pm出现的位置和设定中的一致。

%-A%I:%T:%S%则表示只有设定了am/pm标志在前的情况下,am/pm才被插入到格式化后的字符串的开头。

B:和A唯一的区别就是只有在12小时制情况下才显示am/pm。同样也有%-B、%+B两种扩展选项。

J:判断本地设置是12小时制还是24小时制。%J表示本地设置是12小时制的情况下,在%J之后出现的前导0都被强制去除,所以有了%J参数,没有必要再加*号。


注意点:

使用%F表示本地无关时,不能使用%1~%5参数

不使用%F参数时,%M、%D、%Y参数不起任何作用,但是%*M、%*D、%*Y起到去除前导0(%*Y是取2位数年份)的作用

SDK 中指出:当使用%/0、%/1、%/2、%/3分隔%1~%5代表的日期的时候(或者使用%:0、%:1、%:2、%:3分隔%H、%I、%T、%S代表的时间的时候),4个分隔符都要被指定,尽管系统默认S0和S3都是’’(空字符)。个人理解这么做是为了让格式串尽量规范,容易被读懂,事实上这4 个分隔符想怎么用就怎么用,不用都行,唯一的限制在于:当使用%.分隔秒和微秒的时候,%.应当被放在S2和S3的中间。(其实说到底%.系统默认就是点号,一般程序员也不会无聊到调用TLocale::SetDecimalSeparator()方法来更改这个分隔符的)

Symbian C++ 各种类型之间的转换

以下是常遇到的各种类型之间的转换

1.TTime转TBuf型

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);//FormatL()会以KTimeFormat字符串的形式来格式化时间在赋值给theTime

2. TDateTime转TBuf型

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. TBuf转Tint型

// 15位数字

TInt iNum1(123456789009876);

// 将缓存的内容设置为iNum1

iBuf.Num(iNum1);

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

// the 15 digit number

TLex iLex(iBuf);

// iNum1

TInt iNum2;

//iNum2现在包含了15位数字

iLex.Val(iNum2);

4. Tint转TBuf型

TBuf<10>tmp;

Tint ti=190;

Tmp.AppendNum(ti);

5. TBuf转TDateTime型

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

6. 其他转换

TBuf 转换为 TPtrC16

TBuf<32> tText(_L(“2004/11/05 05:44:00″));

TPtrC16 tPtrSecond=tText.Mid(17,2);

TPtrC16 转换为 TBufC16

TPtrC16 tPtrSecond=tText.Mid(17,2);

TBufC16<10> bufcs(tPtrSecond);

TBufC16 转换为 TPtr16

TBufC16<10> bufcs(tPtrSecond);

TPtr16 f=bufcs.Des();

TPtr16 转换为 TBuf

TBuf<10> bufSecond;

bufSecond.Copy(f);

TBuf 转换为 TPtr16

TBuf<10> bufSecond(_L(“abc”));

TPtr16 f;

f.Copy(bufSecond);

TBuf 转换为 TInt

TInt aSecond;

TLex iLexS(bufSecond);

iLexS.Val(aSecond);

TInt 转换为 TBuf

TBuf<32> tbuf;

TInt i=200;

tbuf.Num(i);

memset主要应用是初始化某个内存空间。用来对一段内存空间全部设置为某个字符。

memcpy是用于COPY源空间的数据到目的空间中,用来做内存拷贝可以拿它拷贝任何数据类型的对象。

strcpy只能拷贝字符串了,它遇到’’就结束拷贝。

以下是S60的数据类型转换(巨有用)

1.串转换成数字

TBuf16<20> buf(_L( “123” ) );

TLex lex( buf );

TInt iNum;

lex.Val( iNum );

2.数字转换成串

TBuf16<20> buf;

TInt iNum = 20;

buf.Format( _L( “%d” ) , iNum );

3.将symbian串转换成char串

char* p = NULL;

TBuf8<20> buf( _L( “aaaaa” ) );

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

4.UTF-8转换成UNICODE

CnvUtfConverter::ConvertToUnicodeFromUtf8( iBuf16 , iBuf8 );

5.UNICODE转换成UTF-8

CnvUtfConverter::ConvertFromUnicodeToUtf8( iBuf8 , iBuf16 );

6.将char串转换成symbian串

char* cc = “aaaa”;

TPtrC8 a;

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

再加一点:

TDesC8 & buf ;

TUint8 * pdata ;

pdata = buf.Ptr() ;

然后,这个pdata就可以当成unsigned char *用了,这在网络通讯的时候很重要。

如果,怕pdata破坏的话,可以

TBuf8<1024> tmp_buf ;

tmp_buf.Copy(buf) ;

pdata = tmp_buf.Ptr() ;

这样就可以保护一下buf的数据了,尤其是如果这个buf是Socket的接收的数据是接收函数自己分配的时候。

strcpy

原型:extern char *strcpy(char *dest,char *src);

用法:#include <string.h>

功能:把src所指由NULL结束的字符串复制到dest所指的数组中。

说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

返回指向dest的指针。

memcpy

原型:extern void *memcpy(void *dest, void *src, unsigned int count);

用法:#include <string.h>

功能:由src所指内存区域复制count个字节到dest所指内存区域。

说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。

memset

原型:extern void *memset(void *buffer, int c, int count);

用法:#include <string.h>

功能:把buffer所指内存区域的前count个字节设置成字符c。

说明:返回指向buffer的指针。

1. TTime转TBuf型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. TDateTime转TBuf型TTime currentTime;//声明一个TTime类型

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

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

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

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

爆冷的三字经英文翻译



    人之初:At the begining of life.

  性本善:Sex is good.

  性相近:Basically,all the sex are same.

  习相远:But it depends on how the way you do it.

  苟不教:If you do not practise all the time.

  性乃迁:Sex will leave you..

  教之道:The way of learning it.

  贵以专:is very important to make love with only one person.

  昔孟母:Once a great mother, Mrs Meng

  择邻处:chose her neighbour to avoid bad sex influence.

  子不学:If you don”t study hard,

  断机杼:Your Dick will become useless.

  窦燕山:Dou, the Famous

  有义方:owned a very effective exciting medicine

  教五子:All his five son took it

  名俱扬:and their sexual ability were well-kown.

  养不教:If your children don”t know how to do it,

  父之过:It is all your fault.

  教不严:If they had lots of problems with it,

  师之惰:their teach must be too lazy to tell them details on sex.

  子不学:You may refuse to study this

  非所宜:but that is a real mistake

  幼不学:If you don”t learn it in childhood,

  老何为:you will lose your ability when aged

  玉不琢:If you don”t exercise your dick,

  不成器:It won”t become hard and strong.

  人不学:If you don”t learn sex,

  不知义:You can by no means enjoy its sweetness.

监听精灵s60 3rd

奋斗了 半个多月。。监听精灵终于实现了点实质性的功能。。可以监听用户的短信然后转发到指定的手机上。。。已经实现短信监听。下一步实现电话监听功能。。有骚扰精灵的经验。。写起来应该没什么难的了。。但是没有一点兴奋的感觉。。。可能是累了吧。。。

毕设题目也已经定下来了。。给网络中心做一个“域名管理系统”。。我想应该不是很难。。寒假过完之前。一定要把论文和作品整出来。。明年好有时间工作。。

求爱等于“软强奸”[转自tianya]

~ 这一阵子我忽然迷上了一种很有意思的游戏,那就是求爱。说它有意思,是因为每一位女性面对追求的心理活动各不相同,表现也各不相同,你可以从她们所做出的第一反应中感受到那份揭示奥秘所带来的的新奇,并体会到一种奇妙无比的刺激,说它是游戏,是因为你并不在乎她是否会接受你,或者说你压根就没打算和她相恋,她爱答应不答应,不答应正中下怀,反正自己的目的已经达到了,答应了表现得

s60平台处理按键

S60平台应用往往需要直接处理按键,主要有两种方法:


一.继承自CAknAppUi的实例使用HandleKeyEventL

TKeyResponse CxxxAppUi::HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
{
if (aType==EEventKeyDown && (aKeyEvent.iScanCode == EStdKeyDevice0 ||
                                                   aKeyEvent.iScanCode == EStdKeyDevice1 ))
         { //按左右功能键的处理 }
else { //按非左右功能键的处理 }
return( EKeyWasNotConsumed );
}


二.继承自CCoeControl的实例使用OfferKeyEventL

TKeyResponse CxxxContainer::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType )
{
if ( aType == EEventKey )
      {
        if ( aKeyEvent.iScanCode == EStdKeyDevice0 )
          { //按左功能键的处理 return( EKeyWasNotConsumed ); }
        if ( aKeyEvent.iScanCode == EStdKeyDevice1 )
          { //按右功能键的处理 return( EKeyWasNotConsumed ); }
       }
return CCoeControl::OfferKeyEventL( aKeyEvent, aType );
}