青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

HUUYUU

2008年7月10日 #

Freetype學(xué)習(xí)筆記

     摘要: 轉(zhuǎn)載時(shí)請(qǐng)注明出處和作者聯(lián)系方式:http://blog.csdn.net/absurd 作者聯(lián)系方式:Li XianJing <xianjimli at hotmail dot com> 更新時(shí)間:2006-12-19   GTK+(基于DirectFB)的字體繪制是通過(guò)pango+freetype+fontconfig三者協(xié)作來(lái)完成的,其中,fontconfig負(fù)責(zé)...  閱讀全文

posted @ 2008-07-10 22:22 HUYU 閱讀(1378) | 評(píng)論 (1)編輯 收藏

2008年1月22日 #

寫(xiě)operator new和operator delete時(shí)要遵循常規(guī)

自己重寫(xiě)operator new時(shí),很重要的一點(diǎn)是函數(shù)提供的行為要和系統(tǒng)缺省的operator new一致。實(shí)際做起來(lái)也就是:要有正確的返回值;可用內(nèi)存不夠時(shí)要調(diào)用出錯(cuò)處理函數(shù);處理好0字節(jié)內(nèi)存請(qǐng)求的情況。此外,還要避免不小心隱藏了標(biāo)準(zhǔn)形式的new。

非類成員形式的operator new的偽代碼:

void * operator new(size_t size)        // operator new還可能有其它參數(shù)
{                                      

  if (size == 0)                      // 處理0字節(jié)請(qǐng)求時(shí),
  {

        size = 1;                            // 把它當(dāng)作1個(gè)字節(jié)請(qǐng)求來(lái)處理

  }                                    
  while (1)

{
    分配size字節(jié)內(nèi)存;

      if (分配成功)
           return (指向內(nèi)存的指針);

    // 分配不成功,找出當(dāng)前出錯(cuò)處理函數(shù)
      new_handler globalhandler = set_new_handler(0);
     set_new_handler(globalhandler);

      if (globalhandler) (*globalhandler)();
      else throw std::bad_alloc();
  }
}

 

為特定類寫(xiě)的new往往沒(méi)有考慮該類被繼承的情況,使用sizeof(父類)獲得大小,但是如果發(fā)生子類調(diào)用父類的new時(shí),往往

會(huì)出錯(cuò),子類的size往往大于父類的size。最好父類的new應(yīng)該這么寫(xiě):

void * base::operator new(size_t size)
{
  if (size != sizeof(base))                  // 如果數(shù)量“錯(cuò)誤”,讓標(biāo)準(zhǔn)operator new,精華部分。
    return ::operator new(size);        // 去處理這個(gè)請(qǐng)求
                                                         //

  ...                                                    // 否則處理這個(gè)請(qǐng)求
}

 

對(duì)于operator delete(以及它的伙伴operator delete[]),情況更簡(jiǎn)單。所要記住的只是,c++保證刪除空指針永遠(yuǎn)是安全的,所以你要充分地應(yīng)用這一保證。

下面是非類成員形式的operator delete的偽代碼:
void operator delete(void *rawmemory)
{
  if (rawmemory == 0) return;   //如果指針為空,返回
                                 //

  釋放rawmemory指向的內(nèi)存;

  return;
}

 

這個(gè)函數(shù)的類成員版本也簡(jiǎn)單,只是還必須檢查被刪除的對(duì)象的大小。假設(shè)類的operator new將“錯(cuò)誤”大小的分配請(qǐng)求轉(zhuǎn)給::operator new,那么也必須將“錯(cuò)誤”大小的刪除請(qǐng)求轉(zhuǎn)給::operator delete:

void base::operator delete(void *rawmemory, size_t size)
{
  if (rawmemory == 0) return;          // 檢查空指針

  if (size != sizeof(base))                 // 如果size"錯(cuò)誤",

{    
    ::operator delete(rawmemory);  // 讓標(biāo)準(zhǔn)operator來(lái)處理請(qǐng)求
    return;                       
  }

  釋放指向rawmemory的內(nèi)存;

  return;
}

有關(guān)operator new和operator delete(以及他們的數(shù)組形式)的規(guī)定不是那么麻煩,重要的是必須遵守它。只要內(nèi)存分配程序支持new-handler函數(shù)并正確地處理了零內(nèi)存請(qǐng)求,就差不多了;如果內(nèi)存釋放程序又處理了空指針,那就沒(méi)其他什么要做的了。至于在類成員版本的函數(shù)里增加繼承支持,那將很快就可以完成。

posted @ 2008-01-22 09:42 HUYU 閱讀(423) | 評(píng)論 (0)編輯 收藏

2008年1月10日 #

堆和棧的區(qū)別

一、預(yù)備知識(shí)—程序的內(nèi)存分配
    一個(gè)由c/C++編譯的程序占用的內(nèi)存分為以下幾個(gè)部分
    1、棧區(qū)(stack)— 由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。
    2、堆區(qū)(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表,呵呵。
    3、全局區(qū)(靜態(tài)區(qū))(static)—,全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 - 程序結(jié)束后有系統(tǒng)釋放
    4、文字常量區(qū)—常量字符串就是放在這里的。 程序結(jié)束后由系統(tǒng)釋放
    5、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。


例子程序
這是一個(gè)前輩寫(xiě)的,非常詳細(xì)
//main.cpp
int a = 0; 全局初始化區(qū)
char *p1; 全局未初始化區(qū)
main()
{
int b; 棧
char s[] = "abc"; 棧
char *p2; 棧
char *p3 = "123456"; 123456\0在常量區(qū),p3在棧上。
static int c =0; 全局(靜態(tài))初始化區(qū)
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得來(lái)得10和20字節(jié)的區(qū)域就在堆區(qū)。
strcpy(p1, "123456"); 123456\0放在常量區(qū),編譯器可能會(huì)將它與p3所指向的"123456"優(yōu)化成一個(gè)地方。
}


二、堆和棧的理論知識(shí)

2.1申請(qǐng)方式
stack:
由系統(tǒng)自動(dòng)分配。 例如,聲明在函數(shù)中一個(gè)局部變量 int b; 系統(tǒng)自動(dòng)在棧中為b開(kāi)辟空間
heap:
需要程序員自己申請(qǐng),并指明大小,在c中malloc函數(shù)
如p1 = (char *)malloc(10);
在C++中用new運(yùn)算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在棧中的。

2.2申請(qǐng)后系統(tǒng)的響應(yīng)
棧:只要棧的剩余空間大于所申請(qǐng)空間,系統(tǒng)將為程序提供內(nèi)存,否則將報(bào)異常提示棧溢出。
堆:首先應(yīng)該知道操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請(qǐng)時(shí),
會(huì)遍歷該鏈表,尋找第一個(gè)空間大于所申請(qǐng)空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空閑結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序,另外,對(duì)于大多數(shù)系統(tǒng),會(huì)在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語(yǔ)句才能正確的釋放本內(nèi)存空間。另外,由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請(qǐng)的大小,系統(tǒng)會(huì)自動(dòng)的將多余的那部分重新放入空閑鏈表中。

2.3申請(qǐng)大小的限制
棧:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在WINDOWS下,棧的大小是2M(也有的說(shuō)是1M,總之是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請(qǐng)的空間超過(guò)棧的剩余空間時(shí),將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來(lái)存儲(chǔ)的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見(jiàn),堆獲得的空間比較靈活,也比較大。


2.4申請(qǐng)效率的比較
棧由系統(tǒng)自動(dòng)分配,速度較快。但程序員是無(wú)法控制的。
堆是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過(guò)用起來(lái)最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內(nèi)存,他不是在堆,也不是在棧是直接在進(jìn)程的地址空間中保留一快內(nèi)存,雖然用起來(lái)最不方便。但是速度快,也最靈活。

2.5堆和棧中的存儲(chǔ)內(nèi)容
棧: 在函數(shù)調(diào)用時(shí),第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語(yǔ)句的下一條可執(zhí)行語(yǔ)句)的地址,然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。
當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開(kāi)始存的地址,也就是主函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行。
堆:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小。堆中的具體內(nèi)容有程序員安排。

2.6存取效率的比較
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在運(yùn)行時(shí)刻賦值的;
而bbbbbbbbbbb是在編譯時(shí)就確定的;
但是,在以后的存取中,在棧上的數(shù)組比指針?biāo)赶虻淖址?例如堆)快。
比如:
#i nclude
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
對(duì)應(yīng)的匯編代碼
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一種在讀取時(shí)直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,在根據(jù)edx讀取字符,顯然慢了。

2.7小結(jié)
堆和棧的區(qū)別可以用如下的比喻來(lái)看出:
使用棧就象我們?nèi)ワ堭^里吃飯,只管點(diǎn)菜(發(fā)出申請(qǐng))、付錢(qián)、和吃(使用),吃飽了就走,不必理會(huì)切菜、洗菜等準(zhǔn)備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。
使用堆就象是自己動(dòng)手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。



windows進(jìn)程中的內(nèi)存結(jié)構(gòu)


在閱讀本文之前,如果你連
堆棧是什么多不知道的話,請(qǐng)先閱讀文章后面的基礎(chǔ)知識(shí)

接觸過(guò)
編程的人都知道,高級(jí)語(yǔ)言都能通過(guò)變量名來(lái)訪問(wèn)內(nèi)存中的數(shù)據(jù)。那么這些變量在內(nèi)存中是如何存放的呢?程序又是如何使用這些變量的呢?下面就會(huì)對(duì)此進(jìn)行深入的討論。下文中的C語(yǔ)言代碼如沒(méi)有特別聲明,默認(rèn)都使用VC編譯的release版。

首先,來(lái)了解一下 C 語(yǔ)言的變量是如何在內(nèi)存分部的。C 語(yǔ)言有全局變量(Global)、本地變量(Local),靜態(tài)變量(Static)、寄存器變量(Regeister)。每種變量都有不同的分配方式。先來(lái)看下面這段代碼:

#i nclude <stdio.h>

int g1=0, g2=0, g3=0;

int main()
{
static int s1=0, s2=0, s3=0;
int v1=0, v2=0, v3=0;

//打印出各個(gè)變量的內(nèi)存地址

printf("0x%08x\n",&v1); //打印各本地變量的內(nèi)存地址
printf("0x%08x\n",&v2);
printf("0x%08x\n\n",&v3);
printf("0x%08x\n",&g1); //打印各全局變量的內(nèi)存地址
printf("0x%08x\n",&g2);
printf("0x%08x\n\n",&g3);
printf("0x%08x\n",&s1); //打印各靜態(tài)變量的內(nèi)存地址
printf("0x%08x\n",&s2);
printf("0x%08x\n\n",&s3);
return 0;
}

編譯后的執(zhí)行結(jié)果是:

0x0012ff78
0x0012ff7c
0x0012ff80

0x004068d0
0x004068d4
0x004068d8

0x004068dc
0x004068e0
0x004068e4

輸出的結(jié)果就是變量的內(nèi)存地址。其中v1,v2,v3是本地變量,g1,g2,g3是全局變量,s1,s2,s3是靜態(tài)變量。你可以看到這些變量在內(nèi)存是連續(xù)分布的,但是本地變量和全局變量分配的內(nèi)存地址差了十萬(wàn)八千里,而全局變量和靜態(tài)變量分配的內(nèi)存是連續(xù)的。這是因?yàn)楸镜刈兞亢腿?靜態(tài)變量是分配在不同類型的內(nèi)存區(qū)域中的結(jié)果。對(duì)于一個(gè)進(jìn)程的內(nèi)存空間而言,可以在邏輯上分成3個(gè)部份:代碼區(qū),靜態(tài)數(shù)據(jù)區(qū)和動(dòng)態(tài)數(shù)據(jù)區(qū)。動(dòng)態(tài)數(shù)據(jù)區(qū)一般就是“堆棧”。“棧(stack)”和“堆(heap)”是兩種不同的動(dòng)態(tài)數(shù)據(jù)區(qū),棧是一種線性結(jié)構(gòu),堆是一種鏈?zhǔn)浇Y(jié)構(gòu)。進(jìn)程的每個(gè)線程都有私有的“棧”,所以每個(gè)線程雖然代碼一樣,但本地變量的數(shù)據(jù)都是互不干擾。一個(gè)堆棧可以通過(guò)“基地址”和“棧頂”地址來(lái)描述。全局變量和靜態(tài)變量分配在靜態(tài)數(shù)據(jù)區(qū),本地變量分配在動(dòng)態(tài)數(shù)據(jù)區(qū),即堆棧中。程序通過(guò)堆棧的基地址和偏移量來(lái)訪問(wèn)本地變量。


├———————┤低端內(nèi)存區(qū)域
│ …… │
├———————┤
│ 動(dòng)態(tài)數(shù)據(jù)區(qū) │
├———————┤
│ …… │
├———————┤
│ 代碼區(qū) │
├———————┤
│ 靜態(tài)數(shù)據(jù)區(qū) │
├———————┤
│ …… │
├———————┤高端內(nèi)存區(qū)域


堆棧是一個(gè)先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),棧頂?shù)刂房偸切∮诘扔跅5幕刂贰N覀兛梢韵攘私庖幌潞瘮?shù)調(diào)用的過(guò)程,以便對(duì)堆棧在程序中的作用有更深入的了解。不同的語(yǔ)言有不同的函數(shù)調(diào)用規(guī)定,這些因素有參數(shù)的壓入規(guī)則和堆棧的平衡。windows API的調(diào)用規(guī)則和ANSI C的函數(shù)調(diào)用規(guī)則是不一樣的,前者由被調(diào)函數(shù)調(diào)整堆棧,后者由調(diào)用者調(diào)整堆棧。兩者通過(guò)“__stdcall”和“__cdecl”前綴區(qū)分。先看下面這段代碼:

#i nclude <stdio.h>

void __stdcall func(int param1,int param2,int param3)
{
int var1=param1;
int var2=param2;
int var3=param3;
printf("0x%08x\n",?m1); //打印出各個(gè)變量的內(nèi)存地址
printf("0x%08x\n",?m2);
printf("0x%08x\n\n",?m3);
printf("0x%08x\n",&var1);
printf("0x%08x\n",&var2);
printf("0x%08x\n\n",&var3);
return;
}

int main()
{
func(1,2,3);
return 0;
}

編譯后的執(zhí)行結(jié)果是:

0x0012ff78
0x0012ff7c
0x0012ff80

0x0012ff68
0x0012ff6c
0x0012ff70


├———————┤<—函數(shù)執(zhí)行時(shí)的棧頂(ESP)、低端內(nèi)存區(qū)域
│ …… │
├———————┤
│ var 1 │
├———————┤
│ var 2 │
├———————┤
│ var 3 │
├———————┤
│ RET │
├———————┤<—“__cdecl”函數(shù)返回后的棧頂(ESP)
│ parameter 1 │
├———————┤
│ parameter 2 │
├———————┤
│ parameter 3 │
├———————┤<—“__stdcall”函數(shù)返回后的棧頂(ESP)
│ …… │
├———————┤<—棧底(基地址 EBP)、高端內(nèi)存區(qū)域


上圖就是函數(shù)調(diào)用過(guò)程中堆棧的樣子了。首先,三個(gè)參數(shù)以從又到左的次序壓入堆棧,先壓“param3”,再壓“param2”,最后壓入“param1”;然后壓入函數(shù)的返回地址(RET),接著跳轉(zhuǎn)到函數(shù)地址接著執(zhí)行(這里要補(bǔ)充一點(diǎn),介紹UNIX下的緩沖溢出原理的文章中都提到在壓入RET后,繼續(xù)壓入當(dāng)前EBP,然后用當(dāng)前ESP代替EBP。然而,有一篇介紹windows下函數(shù)調(diào)用的文章中說(shuō),在windows下的函數(shù)調(diào)用也有這一步驟,但根據(jù)我的實(shí)際調(diào)試,并未發(fā)現(xiàn)這一步,這還可以從param3和var1之間只有4字節(jié)的間隙這點(diǎn)看出來(lái));第三步,將棧頂(ESP)減去一個(gè)數(shù),為本地變量分配內(nèi)存空間,上例中是減去12字節(jié)(ESP=ESP-3*4,每個(gè)int變量占用4個(gè)字節(jié));接著就初始化本地變量的內(nèi)存空間。由于“__stdcall”調(diào)用由被調(diào)函數(shù)調(diào)整堆棧,所以在函數(shù)返回前要恢復(fù)堆棧,先回收本地變量占用的內(nèi)存(ESP=ESP+3*4),然后取出返回地址,填入EIP寄存器,回收先前壓入?yún)?shù)占用的內(nèi)存(ESP=ESP+3*4),繼續(xù)執(zhí)行調(diào)用者的代碼。參見(jiàn)下列匯編代碼:

;--------------func 函數(shù)的匯編代碼-------------------

:00401000 83EC0C sub esp, 0000000C //創(chuàng)建本地變量的內(nèi)存空間
:00401003 8B442410 mov eax, dword ptr [esp+10]
:00401007 8B4C2414 mov ecx, dword ptr [esp+14]
:0040100B 8B542418 mov edx, dword ptr [esp+18]
:0040100F 89442400 mov dword ptr [esp], eax
:00401013 8D442410 lea eax, dword ptr [esp+10]
:00401017 894C2404 mov dword ptr [esp+04], ecx

……………………(省略若干代碼)

:00401075 83C43C add esp, 0000003C ;恢復(fù)堆棧,回收本地變量的內(nèi)存空間
:00401078 C3 ret 000C ;函數(shù)返回,恢復(fù)參數(shù)占用的內(nèi)存空間
;如果是“__cdecl”的話,這里是“ret”,堆棧將由調(diào)用者恢復(fù)

;-------------------函數(shù)結(jié)束-------------------------


;--------------主程序調(diào)用func函數(shù)的代碼--------------

:00401080 6A03 push 00000003 //壓入?yún)?shù)param3
:00401082 6A02 push 00000002 //壓入?yún)?shù)param2
:00401084 6A01 push 00000001 //壓入?yún)?shù)param1
:00401086 E875FFFFFF call 00401000 //調(diào)用func函數(shù)
;如果是“__cdecl”的話,將在這里恢復(fù)堆棧,“add esp, 0000000C”

聰明的讀者看到這里,差不多就明白緩沖溢出的原理了。先來(lái)看下面的代碼:

#i nclude <stdio.h>
#i nclude <string.h>

void __stdcall func()
{
char lpBuff[8]="\0";
strcat(lpBuff,"AAAAAAAAAAA");
return;
}

int main()
{
func();
return 0;
}

編譯后執(zhí)行一下回怎么樣?哈,“"0x00414141"指令引用的"0x00000000"內(nèi)存。該內(nèi)存不能為"read"。”,“非法操作”嘍!"41"就是"A"的16進(jìn)制的ASCII碼了,那明顯就是strcat這句出的問(wèn)題了。"lpBuff"的大小只有8字節(jié),算進(jìn)結(jié)尾的\0,那strcat最多只能寫(xiě)入7個(gè)"A",但程序?qū)嶋H寫(xiě)入了11個(gè)"A"外加1個(gè)\0。再來(lái)看看上面那幅圖,多出來(lái)的4個(gè)字節(jié)正好覆蓋了RET的所在的內(nèi)存空間,導(dǎo)致函數(shù)返回到一個(gè)錯(cuò)誤的內(nèi)存地址,執(zhí)行了錯(cuò)誤的指令。如果能精心構(gòu)造這個(gè)字符串,使它分成三部分,前一部份僅僅是填充的無(wú)意義數(shù)據(jù)以達(dá)到溢出的目的,接著是一個(gè)覆蓋RET的數(shù)據(jù),緊接著是一段shellcode,那只要著個(gè)RET地址能指向這段shellcode的第一個(gè)指令,那函數(shù)返回時(shí)就能執(zhí)行shellcode了。但是軟件的不同版本和不同的運(yùn)行環(huán)境都可能影響這段shellcode在內(nèi)存中的位置,那么要構(gòu)造這個(gè)RET是十分困難的。一般都在RET和shellcode之間填充大量的NOP指令,使得exploit有更強(qiáng)的通用性。


├———————┤<—低端內(nèi)存區(qū)域
│ …… │
├———————┤<—由exploit填入數(shù)據(jù)的開(kāi)始
│ │
│ buffer │<—填入無(wú)用的數(shù)據(jù)
│ │
├———————┤
│ RET │<—指向shellcode,或NOP指令的范圍
├———————┤
│ NOP │
│ …… │<—填入的NOP指令,是RET可指向的范圍
│ NOP │
├———————┤
│ │
│ shellcode │
│ │
├———————┤<—由exploit填入數(shù)據(jù)的結(jié)束
│ …… │
├———————┤<—高端內(nèi)存區(qū)域


windows下的動(dòng)態(tài)數(shù)據(jù)除了可存放在棧中,還可以存放在堆中。了解C++的朋友都知道,C++可以使用new關(guān)鍵字來(lái)動(dòng)態(tài)分配內(nèi)存。來(lái)看下面的C++代碼:

#i nclude <stdio.h>
#i nclude <iostream.h>
#i nclude <windows.h>

void func()
{
char *buffer=new char[128];
char bufflocal[128];
static char buffstatic[128];
printf("0x%08x\n",buffer); //打印堆中變量的內(nèi)存地址
printf("0x%08x\n",bufflocal); //打印本地變量的內(nèi)存地址
printf("0x%08x\n",buffstatic); //打印靜態(tài)變量的內(nèi)存地址
}

void main()
{
func();
return;
}

程序執(zhí)行結(jié)果為:

0x004107d0
0x0012ff04
0x004068c0

可以發(fā)現(xiàn)用new關(guān)鍵字分配的內(nèi)存即不在棧中,也不在靜態(tài)數(shù)據(jù)區(qū)。VC編譯器是通過(guò)windows下的“堆(heap)”來(lái)實(shí)現(xiàn)new關(guān)鍵字的內(nèi)存動(dòng)態(tài)分配。在講“堆”之前,先來(lái)了解一下和“堆”有關(guān)的幾個(gè)API函數(shù):

HeapAlloc 在堆中申請(qǐng)內(nèi)存空間
HeapCreate 創(chuàng)建一個(gè)新的堆對(duì)象
HeapDestroy 銷毀一個(gè)堆對(duì)象
HeapFree 釋放申請(qǐng)的內(nèi)存
HeapWalk 枚舉堆對(duì)象的所有內(nèi)存塊
GetProcessHeap 取得進(jìn)程的默認(rèn)堆對(duì)象
GetProcessHeaps 取得進(jìn)程所有的堆對(duì)象
LocalAlloc
GlobalAlloc

當(dāng)進(jìn)程初始化時(shí),系統(tǒng)會(huì)自動(dòng)為進(jìn)程創(chuàng)建一個(gè)默認(rèn)堆,這個(gè)堆默認(rèn)所占內(nèi)存的大小為1M。堆對(duì)象由系統(tǒng)進(jìn)行管理,它在內(nèi)存中以鏈?zhǔn)浇Y(jié)構(gòu)存在。通過(guò)下面的代碼可以通過(guò)堆動(dòng)態(tài)申請(qǐng)內(nèi)存空間:

HANDLE hHeap=GetProcessHeap();
char *buff=HeapAlloc(hHeap,0,8);

其中hHeap是堆對(duì)象的句柄,buff是指向申請(qǐng)的內(nèi)存空間的地址。那這個(gè)hHeap究竟是什么呢?它的值有什么意義嗎?看看下面這段代碼吧:

#pragma comment(linker,"/entry:main") //定義程序的入口
#i nclude <windows.h>

_CRTIMP int (__cdecl *printf)(const char *, ...); //定義STL函數(shù)printf
/*---------------------------------------------------------------------------
寫(xiě)到這里,我們順便來(lái)復(fù)習(xí)一下前面所講的知識(shí):
(*注)printf函數(shù)是C語(yǔ)言的標(biāo)準(zhǔn)函數(shù)庫(kù)中函數(shù),VC的標(biāo)準(zhǔn)函數(shù)庫(kù)由msvcrt.dll模塊實(shí)現(xiàn)。
由函數(shù)定義可見(jiàn),printf的參數(shù)個(gè)數(shù)是可變的,函數(shù)內(nèi)部無(wú)法預(yù)先知道調(diào)用者壓入的參數(shù)個(gè)數(shù),函數(shù)只能通過(guò)分析第一個(gè)參數(shù)字符串的格式來(lái)獲得壓入?yún)?shù)的信息,由于這里參數(shù)的個(gè)數(shù)是動(dòng)態(tài)的,所以必須由調(diào)用者來(lái)平衡堆棧,這里便使用了__cdecl調(diào)用規(guī)則。BTW,Windows系統(tǒng)的API函數(shù)基本上是__stdcall調(diào)用形式,只有一個(gè)API例外,那就是wsprintf,它使用__cdecl調(diào)用規(guī)則,同printf函數(shù)一樣,這是由于它的參數(shù)個(gè)數(shù)是可變的緣故。
---------------------------------------------------------------------------*/
void main()
{
HANDLE hHeap=GetProcessHeap();
char *buff=HeapAlloc(hHeap,0,0x10);
char *buff2=HeapAlloc(hHeap,0,0x10);
HMODULE hMsvcrt=LoadLibrary("msvcrt.dll");
printf=(void *)GetProcAddress(hMsvcrt,"printf");
printf("0x%08x\n",hHeap);
printf("0x%08x\n",buff);
printf("0x%08x\n\n",buff2);
}

執(zhí)行結(jié)果為:

0x00130000
0x00133100
0x00133118

hHeap的值怎么和那個(gè)buff的值那么接近呢?其實(shí)hHeap這個(gè)句柄就是指向HEAP首部的地址。在進(jìn)程的用戶區(qū)存著一個(gè)叫PEB(進(jìn)程環(huán)境塊)的結(jié)構(gòu),這個(gè)結(jié)構(gòu)中存放著一些有關(guān)進(jìn)程的重要信息,其中在PEB首地址偏移0x18處存放的ProcessHeap就是進(jìn)程默認(rèn)堆的地址,而偏移0x90處存放了指向進(jìn)程所有堆的地址列表的指針。windows有很多API都使用進(jìn)程的默認(rèn)堆來(lái)存放動(dòng)態(tài)數(shù)據(jù),如windows 2000下的所有ANSI版本的函數(shù)都是在默認(rèn)堆中申請(qǐng)內(nèi)存來(lái)轉(zhuǎn)換ANSI字符串到Unicode字符串的。對(duì)一個(gè)堆的訪問(wèn)是順序進(jìn)行的,同一時(shí)刻只能有一個(gè)線程訪問(wèn)堆中的數(shù)據(jù),當(dāng)多個(gè)線程同時(shí)有訪問(wèn)要求時(shí),只能排隊(duì)等待,這樣便造成程序執(zhí)行效率下降。

最后來(lái)說(shuō)說(shuō)內(nèi)存中的數(shù)據(jù)對(duì)齊。所位數(shù)據(jù)對(duì)齊,是指數(shù)據(jù)所在的內(nèi)存地址必須是該數(shù)據(jù)長(zhǎng)度的整數(shù)倍,DWORD數(shù)據(jù)的內(nèi)存起始地址能被4除盡,WORD數(shù)據(jù)的內(nèi)存起始地址能被2除盡,x86 CPU能直接訪問(wèn)對(duì)齊的數(shù)據(jù),當(dāng)他試圖訪問(wèn)一個(gè)未對(duì)齊的數(shù)據(jù)時(shí),會(huì)在內(nèi)部進(jìn)行一系列的調(diào)整,這些調(diào)整對(duì)于程序來(lái)說(shuō)是透明的,但是會(huì)降低運(yùn)行速度,所以編譯器在編譯程序時(shí)會(huì)盡量保證數(shù)據(jù)對(duì)齊。同樣一段代碼,我們來(lái)看看用VC、Dev-C++和lcc三個(gè)不同編譯器編譯出來(lái)的程序的執(zhí)行結(jié)果:

#i nclude <stdio.h>

int main()
{
int a;
char b;
int c;
printf("0x%08x\n",&a);
printf("0x%08x\n",&b);
printf("0x%08x\n",&c);
return 0;
}

這是用VC編譯后的執(zhí)行結(jié)果:
0x0012ff7c
0x0012ff7b
0x0012ff80
變量在內(nèi)存中的順序:b(1字節(jié))-a(4字節(jié))-c(4字節(jié))。

這是用Dev-C++編譯后的執(zhí)行結(jié)果:
0x0022ff7c
0x0022ff7b
0x0022ff74
變量在內(nèi)存中的順序:c(4字節(jié))-中間相隔3字節(jié)-b(占1字節(jié))-a(4字節(jié))。

這是用lcc編譯后的執(zhí)行結(jié)果:
0x0012ff6c
0x0012ff6b
0x0012ff64
變量在內(nèi)存中的順序:同上。

三個(gè)編譯器都做到了數(shù)據(jù)對(duì)齊,但是后兩個(gè)編譯器顯然沒(méi)VC“聰明”,讓一個(gè)char占了4字節(jié),浪費(fèi)內(nèi)存哦。


基礎(chǔ)知識(shí):
堆棧是一種簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu),是一種只允許在其一端進(jìn)行插入或刪除的線性表。允許插入或刪除操作的一端稱為棧頂,另一端稱為棧底,對(duì)堆棧的插入和刪除操作被稱為入棧和出棧。有一組CPU指令可以實(shí)現(xiàn)對(duì)進(jìn)程的內(nèi)存實(shí)現(xiàn)堆棧訪問(wèn)。其中,POP指令實(shí)現(xiàn)出棧操作,PUSH指令實(shí)現(xiàn)入棧操作。CPU的ESP寄存器存放當(dāng)前線程的棧頂指針,EBP寄存器中保存當(dāng)前線程的棧底指針。CPU的EIP寄存器存放下一個(gè)CPU指令存放的內(nèi)存地址,當(dāng)CPU執(zhí)行完當(dāng)前的指令后,從EIP寄存器中讀取下一條指令的內(nèi)存地址,然后繼續(xù)執(zhí)行。

 <br>

堆(Heap)棧(Stack)

1、內(nèi)存分配方面:

    堆:一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式是類似于鏈表。可能用到的關(guān)鍵字如下:newmallocdeletefree等等。

    棧:由編譯器(Compiler)自動(dòng)分配釋放,存放函數(shù)的參數(shù)值局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

2、申請(qǐng)方式方面:

    堆:需要程序員自己申請(qǐng),并指明大小。在c中malloc函數(shù)如p1 = (char *)malloc(10);在C++中用new運(yùn)算符,但是注意p1、p2本身是在棧中的。因?yàn)樗麄冞€是可以認(rèn)為是局部變量。

    棧:由系統(tǒng)自動(dòng)分配。 例如,聲明在函數(shù)中一個(gè)局部變量 int b;系統(tǒng)自動(dòng)在棧中為b開(kāi)辟空間。

3、系統(tǒng)響應(yīng)方面:

    堆:操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請(qǐng)時(shí),會(huì)遍歷該鏈表,尋找第一個(gè)空間大于所申請(qǐng)空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空閑結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序,另外,對(duì)于大多數(shù)系統(tǒng),會(huì)在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣代碼中的delete語(yǔ)句才能正確的釋放本內(nèi)存空間。另外由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請(qǐng)的大小,系統(tǒng)會(huì)自動(dòng)的將多余的那部分重新放入空閑鏈表中。

    棧:只要棧的剩余空間大于所申請(qǐng)空間,系統(tǒng)將為程序提供內(nèi)存,否則將報(bào)異常提示棧溢出。

4、大小限制方面:

    堆:是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來(lái)存儲(chǔ)的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見(jiàn),堆獲得的空間比較靈活,也比較大。

    棧:在Windows下, 棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴?strong>系統(tǒng)預(yù)先規(guī)定好的,在WINDOWS下,棧的大小是固定的(是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請(qǐng)的空間超過(guò)棧的剩余空間時(shí),將提示overflow。因此,能從棧獲得的空間較小。

5、效率方面:

    堆:是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過(guò)用起來(lái)最方便,另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內(nèi)存,他不是在堆,也不是在棧是直接在進(jìn)程的地址空間中保留一快內(nèi)存,雖然用起來(lái)最不方便。但是速度快,也最靈活。

    棧:由系統(tǒng)自動(dòng)分配,速度較快。但程序員是無(wú)法控制的。

6、存放內(nèi)容方面:

    堆:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小。堆中的具體內(nèi)容有程序員安排。

    棧:在函數(shù)調(diào)用時(shí)第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語(yǔ)句的下一條可執(zhí)行語(yǔ)句)的地址然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧,然后是函數(shù)中的局部變量。 注意: 靜態(tài)變量是不入棧的。當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開(kāi)始存的地址,也就是主函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行

7、存取效率方面:

    堆:char *s1 = "Hellow Word";是在編譯時(shí)就確定的;

    棧:char s1[] = "Hellow Word"; 是在運(yùn)行時(shí)賦值的;用數(shù)組比用指針?biāo)俣纫煲恍驗(yàn)橹羔樤诘讓訁R編中需要用edx寄存器中轉(zhuǎn)一下,而數(shù)組在棧上直接讀取。


 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1925576

posted @ 2008-01-10 13:22 HUYU 閱讀(462) | 評(píng)論 (0)編輯 收藏

2007年1月19日 #

Variable Parameters Print Example

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

#include "drm_korea_def.h"

#ifdef __KDRM_FSTRACE

#define LOG_BUFFER_SIZE 512
#define LOG_LINE_NUM  16

#ifdef WIN32
#define LOG_FILE     FILE *
#define LOG_OPEN(s, m)   fopen(s, m)
#define LOG_CLOSE(hLog)   fclose(hLog)
#define LOG_READ (hLog, p, x)  fread (p, x, 1, hLog)
#define LOG_WRITE(hLog, p, x) fwrite(p, x, 1, hLog)
#define LOG_PUTC(hLog, c)  fputc(c, hLog)
#define LOG_PUTS(hLog, s)  fputs(s, hLog)
#else
#define LOG_FILE     int32_t
#define LOG_OPEN(s, m)   Fopen((uint8_t *)s, (uint8_t *)m)
#define LOG_CLOSE(hLog)   Fclose(hLog)
#define LOG_READ (hLog, p, x)  Fread (hLog,  p, x)
#define LOG_WRITE(hLog, p, x) Fwrite(hLog, p, x)
#define LOG_PUTC(hLog, c)  Fputc(hLog, c)
#define LOG_PUTS(hLog, s)  Fputs(hLog, (uint8_t *)s)
#endif

static LOG_FILE fpLogfile;
static char logBuffer[LOG_BUFFER_SIZE];

void log_Init(char *logName)
{
 fpLogfile = LOG_OPEN(logName, "w+");

 if(fpLogfile > 0)
 {
  log_Print("\r\n====> Starting ... :%s %s\r\n", __TIME__, __FILE__);
 }
}

void log_Print(char *logFormat, ...)
{
 if(fpLogfile > 0)
 {
  va_list va;
  int len;

  va_start(va, logFormat);
  len = vsprintf(logBuffer, logFormat, va);
  va_end(va);

  logBuffer[len+1] = 0;

  LOG_PUTS(fpLogfile, logBuffer);
 }
}

char Hex2Dec(unsigned char bHex)
{
 bHex &= 0x0F;
 bHex += bHex<10? '0': 'A' - 10;

 return bHex;
}

void log_Dump(const unsigned char  *pCache, int u32Size, bool bBinary)
{
 int i, stride;
 unsigned char *p = (unsigned char  *)pCache;
 char cTmp;

 if(fpLogfile < 0)
  return;

 if(bBinary)
 {
  for(; p<pCache+u32Size; p+=LOG_BUFFER_SIZE)
  {
   stride = (p+LOG_BUFFER_SIZE <= pCache+u32Size)? LOG_BUFFER_SIZE: u32Size%LOG_BUFFER_SIZE;
   LOG_WRITE(fpLogfile, p, stride);
  }
 }
 else
 {
  for(; p<pCache+u32Size; p+=LOG_LINE_NUM)
  {
   stride = (p+LOG_LINE_NUM <= pCache+u32Size)? LOG_LINE_NUM:u32Size%LOG_LINE_NUM;

   for(i=0; i<stride; i++)
   {
    cTmp = Hex2Dec((p[i]&0xF0) >> 4);
    LOG_PUTC(fpLogfile, cTmp);
    cTmp = Hex2Dec(p[i]&0x0F);
    LOG_PUTC(fpLogfile, cTmp);
    LOG_PUTC(fpLogfile, ' ');
    if(i== (LOG_LINE_NUM/2 - 1))
    {
     LOG_PUTC(fpLogfile, '-');
     LOG_PUTC(fpLogfile, ' ');
    }
   }

   LOG_PUTC(fpLogfile, '\n');
  }
 }
}

void log_Terminate(void)
{
 if(fpLogfile > 0)
 {
  log_Print("<==== Stopping ... :%s\r\n", __TIME__);
  LOG_CLOSE(fpLogfile);
 }
}

#endif //__KDRM_FSTRACE

posted @ 2007-01-19 17:55 HUYU 閱讀(349) | 評(píng)論 (0)編輯 收藏

2006年11月10日 #

FreeType2研究

FreeType2研究

最近學(xué)習(xí)狀態(tài)不佳,感覺(jué)什么都想做卻什么也做不下去,浮躁之極。大的庫(kù)一下子研究不下來(lái),索性找一下小庫(kù)來(lái)看看。
游戲里面一般都涉及到文本、壓縮、圖像、腳本的概念,為了將來(lái)有機(jī)會(huì)研究游戲所以先下手這些小庫(kù),不求甚解只求用好。

先從字體著手,F(xiàn)reeType字體作為一種字體文件編程開(kāi)發(fā)包,廣泛易用在游戲里面。網(wǎng)上漢語(yǔ)資料比較少,只能看它的faq。翻譯了部分如下:

FreeType 2 Library

FAQ

(當(dāng)前下載地址: http://sourceforge.net/project/showfiles.php?group_id=3157 版本 2.2.1

1、? FreeType2 是什么?

它是一個(gè)為各種應(yīng)用程序提供通用的字體文件訪問(wèn)的軟件包。尤其值得注意的以下特性:

l???????? 提供統(tǒng)一的字體文件訪問(wèn)接口。支持位圖和向量格式,包括 TrueType OpenType Typel CID CFF Windows FON/FNT X11 PCF

l???????? 提供高效反走樣的基于 256 灰度級(jí)的位圖字形的生產(chǎn)。

l???????? 模塊清晰,每種字體格式對(duì)于一個(gè)模塊。類庫(kù)的構(gòu)建可以按照你需要支持的格式進(jìn)行裁減以減小代碼尺寸。(最小的反走樣 FreeType 庫(kù) <30Kb

2、? FreeType2 能做什么?

FT2 已經(jīng)易用于許多領(lǐng)域。例如:

l???????? 圖形子系統(tǒng)和文本顯示庫(kù)

l???????? 文本排版(布局、分頁(yè)、渲染)

l???????? 字體識(shí)別和轉(zhuǎn)換工具

一般來(lái)說(shuō),該庫(kù)使得你能輕松的操縱字體文件。

3、? FreeType2 不能做什么?

FT2 并不包含大量豐富的高級(jí)特性,它只定位于出色的字體服務(wù)。也就是說(shuō)下面的一些特性 FT2 類庫(kù)并不直接提供支持,然而你可以以它為基礎(chǔ)在上層進(jìn)行實(shí)現(xiàn):

l???????? 任意表面的文字渲染

FT2 不是圖形庫(kù)所以它僅支持兩種象素格式的文本渲染: 1-bit 的單色位圖和 8-bit 的灰度象素。

如果你需要繪制其它格式的表面(例如 24-bit RGB 象素),你就得選擇其它你喜愛(ài)的圖形庫(kù)來(lái)做。

注意:為了渲染向量輪廓文本而不是放走樣的象素,應(yīng)用程序可以提供自己的渲染回調(diào)以繪制或者直接組合反走樣文本到任意目標(biāo)表面。

l???????? 文本緩存

每次從字體中請(qǐng)求文本圖象, FT2 都要解析字體文件 / 流相關(guān)部分,通過(guò)它的字體格式進(jìn)行解釋。對(duì)于某些特殊格式可能會(huì)很慢包括像 TrueType (或者 Type1 )這樣的向量字體。

注意:自從 2.0.1 版本開(kāi)始 FT2 提供了一個(gè) beta 版本的緩存子系統(tǒng)。當(dāng)然你還是可以寫(xiě)自己的緩存來(lái)滿足某種特殊需求。

l???????? 文本布局

不支持文本布局操作。高級(jí)操作例如文本替換、字距調(diào)整、兩端調(diào)整等都不屬于字體服務(wù)本身職責(zé)。

4、? FreeType2 可移植性?

FT2 源碼可移植性很好由于以下原因:

l???????? 代碼書(shū)寫(xiě)遵循 ANSI C 標(biāo)準(zhǔn)

l???????? 對(duì)于各種編譯警告我們都謹(jǐn)慎的避免。當(dāng)前代碼在很多編譯器上編譯通過(guò)且沒(méi)有產(chǎn)生一條警告。

l???????? 庫(kù)沒(méi)有使用任何硬編碼,是嵌入式系統(tǒng)開(kāi)發(fā)的一個(gè)好的選擇。(例如它能夠直接在 ROM 中運(yùn)行)

同時(shí),我們盡最大努力確保庫(kù)的高效、緊湊和友好性。

5、? FreeType2 FreeType1.x 的區(qū)別?

最大的區(qū)別就是:

l???????? FT1 僅支持 TrueType 格式,而 FT2 支持很多格式。

l???????? FT2 APIs FT1 APIs 簡(jiǎn)單且強(qiáng)大。

l???????? FT1 包括 OpenType 文本布局處理擴(kuò)展,而 FT2 中則不包括而是移到獨(dú)立的工程里面―― FreeType Layout 。( FT 布局目前無(wú)法獲取)

6、? FreeType2 是否兼容 FreeType 1.x

FreeType2 不直接兼容 FreeType 1.x ,但是我們可以提供一個(gè)二進(jìn)制兼容層使得應(yīng)用程序重鏈接到新版本。我們最終放棄了這種想法因?yàn)閮蓚€(gè)版本可以共存在一個(gè)系統(tǒng)中。(沒(méi)有命名沖突)

FT2 API 1.x 簡(jiǎn)單且強(qiáng)大,所以我們鼓勵(lì)你采用新版本,這樣可以使你減少很多不必要的工作。

7、? 是否可以使用 FreeType2 編輯字體或者創(chuàng)建新字體?

答案是明確的:不可以。因?yàn)樵搸?kù)設(shè)計(jì)明確,用較少代碼和內(nèi)存讀取字體文件。所以我們不打算以任何方式在字體引擎里面支持編輯或者創(chuàng)建功能,因?yàn)檫@樣將導(dǎo)致整個(gè)代碼重寫(xiě)。這并不意味我們將來(lái)不會(huì)引入字體編輯 / 創(chuàng)建功能庫(kù),這取決于需求(或者說(shuō)有多少人愿意為此買(mǎi)單)。

在我們正式發(fā)布前不要在這方面進(jìn)行揣測(cè),對(duì)我們而言這個(gè)項(xiàng)目存在其他一些更重要的部分需要解決(像文字布局、文本緩存)。

編譯 & 配置

1、? 如何編譯 FreeType2 庫(kù)?

可以采取多種編譯方式,在 freetype2/docs/build 下有詳細(xì)說(shuō)明文檔。

這里介紹最簡(jiǎn)單的基于 VS IDE 的編譯方式。 freetype\builds\win32\visualc 下有 VC6 VC7.1 的工作區(qū)文件。 VC6 打開(kāi)后直接編譯,有幾個(gè)警告。



光看或許無(wú)法到感性認(rèn)識(shí),于是來(lái)兩個(gè)demo。網(wǎng)上比較少,我是參考nehe教程寫(xiě)的。總體來(lái)說(shuō)會(huì)簡(jiǎn)單使用了,如果想深入了解怕是非看他的document不可。
簡(jiǎn)單使用示例

FT_Library????pFTLib???????? = ?NULL;
????FT_Face????????pFTFace????????
= ?NULL;
????FT_Error????error????????
= ? 0 ;
????
// ?Init?FreeType?Lib?to?manage?memory
????error? = ?FT_Init_FreeType( & pFTLib);
????
if (error)
????
{
????????pFTLib?
= ? 0 ;
????????printf(
" There?is?some?error?when?Init?Library " );
????????
return ? - 1 ;
????}


????
// ?create?font?face?from?font?file
????error? = ?FT_New_Face(pFTLib,? " C:\\WINDOWS\\Fonts\\arial.ttf " ,? 0 ,? & pFTFace);
????
if ( ! error)
????
{
????????FT_Set_Char_Size(pFTFace,?
16 << 6 ,? 16 << 6 ,? 300 ,? 300 );
????????FT_Glyph????glyph;
????????
// ?load?glyph?'C'
????????FT_Load_Glyph(pFTFace,?FT_Get_Char_Index(pFTFace,? 67 ),?FT_LOAD_DEFAULT);
????????error?
= ?FT_Get_Glyph(pFTFace -> glyph,? & glyph);
????????
if ( ! error)
????????
{
????????????
// ?convert?glyph?to?bitmap?with?256?gray
????????????FT_Glyph_To_Bitmap( & glyph,?ft_render_mode_normal,? 0 ,? 1 );
????????????FT_BitmapGlyph????bitmap_glyph?
= ?(FT_BitmapGlyph)glyph;
????????????FT_Bitmap
& ????bitmap? = ?bitmap_glyph -> bitmap;
????????????
for ( int ?i = 0 ;?i < bitmap.rows;? ++ i)
????????????
{
????????????????
for ( int ?j = 0 ;?j < bitmap.width;? ++ j)
????????????????
{
????????????????????
// ?if?it?has?gray>0?we?set?show?it?as?1,?o?otherwise
????????????????????printf( " %d " ,?bitmap.buffer[i * bitmap.width + j] ? 1 : 0 );
????????????????}

????????????????printf(
" \n " );
????????????}

????????????
// ?free?glyph
????????????FT_Done_Glyph(glyph);
????????????glyph?
= ?NULL;
????????}

????????
// ?free?face
????????FT_Done_Face(pFTFace);
????????pFTFace?
= ?NULL;
????}


????
// ?free?FreeType?Lib
????FT_Done_FreeType(pFTLib);
????pFTLib?
= ?NULL;

posted @ 2006-11-10 23:00 HUYU 閱讀(2197) | 評(píng)論 (5)編輯 收藏

2006年10月30日 #

從笑話中悟出C++開(kāi)發(fā)管理之"道"

1. 程序員寫(xiě)出自認(rèn)為沒(méi)有Bug的代碼。

2. 軟件測(cè)試,發(fā)現(xiàn)了20個(gè)Bug。

3. 程序員修改了10個(gè)Bug,并告訴測(cè)試組另外10個(gè)不是Bug。

4. 測(cè)試組發(fā)現(xiàn)其中5個(gè)改動(dòng)根本無(wú)法工作,同時(shí)又發(fā)現(xiàn)了15個(gè)新Bug。

5. 重復(fù)3次步驟3和步驟4。

6. 鑒于市場(chǎng)方面的壓力,為了配合當(dāng)初制定的過(guò)分樂(lè)觀的發(fā)布時(shí)間表,產(chǎn)品終于上市了。

7. 用戶發(fā)現(xiàn)了137個(gè)新Bug。

8. 已經(jīng)領(lǐng)了項(xiàng)目獎(jiǎng)金的程序員不知跑到哪里去了。

9. 新組建的項(xiàng)目組修正了差不多全部137個(gè)Bug,但又發(fā)現(xiàn)了456個(gè)新Bug。

10. 最初那個(gè)程序員從斐濟(jì)給飽受拖欠工資之苦的測(cè)試組寄來(lái)了一張明信片。整個(gè)測(cè)試組集體辭職.

11. 公司被競(jìng)爭(zhēng)對(duì)手惡意收購(gòu)。收購(gòu)時(shí),軟件的最終版本包含783個(gè)Bug。

12. 新CEO走馬上任。公司雇了一名新程序員重寫(xiě)該軟件。

13. 程序員寫(xiě)出自認(rèn)為沒(méi)有Bug的代碼。

  要我說(shuō),如果真有這樣的公司,不倒閉對(duì)不起人民。

 這個(gè)笑話從程序員開(kāi)始,到程序員結(jié)束,從頭到尾都在說(shuō)程序員的不是。但是我要說(shuō)的是,這完全是管理者的失敗,從整個(gè)過(guò)程中,看不到任何管理工作。這種管理者不但無(wú)知無(wú)能,還很無(wú)恥——將自己的失敗責(zé)任推給程序員。

 1、程序員憑什么證明他的代碼沒(méi)有BUG?有Test case嗎?有Code review嗎?這個(gè)環(huán)節(jié)管理缺失。

 2、測(cè)試發(fā)現(xiàn)BUG有進(jìn)行BUG管理嗎?有跟蹤嗎?這個(gè)環(huán)節(jié)管理缺失。
 3、憑什么證明程序員已經(jīng)把那10個(gè)BUG修改好了?另10個(gè)又為什么不是BUG?BUG的評(píng)價(jià)標(biāo)準(zhǔn)難道是程序員說(shuō)了算?這個(gè)環(huán)節(jié)管理缺失。

 4、5個(gè)不能工作的BUG修改問(wèn)題有沒(méi)有追究責(zé)任?增加新BUG是修改過(guò)程中不可避免的事情,但是如果有有效的單元測(cè)試機(jī)制,可以大大減少這種情況。這個(gè)環(huán)節(jié)管理缺失。

 5、迭代是正常的,但是問(wèn)題處理于發(fā)散而不是收斂發(fā)展,可見(jiàn)沒(méi)有有效的管理調(diào)控。這個(gè)環(huán)節(jié)管理缺失。

 6、過(guò)于樂(lè)觀的時(shí)間表和不可能達(dá)到的最后期限,都表現(xiàn)出管理者的無(wú)知和無(wú)能。而在這樣的情況下強(qiáng)行推出產(chǎn)品,那就是無(wú)知者無(wú)畏了。

 7、這是對(duì)用戶的不負(fù)責(zé)任,管理者要負(fù)最大的責(zé)任。

 8、這樣的情況還能發(fā)項(xiàng)目獎(jiǎng)金,只能說(shuō)管理者不是一般的愚蠢。

 9、管理工作沒(méi)有任何的改進(jìn),問(wèn)題仍然處于發(fā)散迭代狀態(tài)。管理工作依然沒(méi)有到位。

 10、拖欠測(cè)試部門(mén)工資體現(xiàn)出管理者對(duì)質(zhì)量管理工作的忽視以及對(duì)人力資源管理方面一無(wú)所知。

 11、送被收購(gòu)者兩個(gè)字:活該。送收購(gòu)者兩個(gè)字:瞎眼。

 12、可見(jiàn)新管理者與原管理者半斤八兩,都沒(méi)有認(rèn)識(shí)到問(wèn)題的根本所在。不過(guò)也只有這樣的管理者才會(huì)作出收購(gòu)這種公司的決策。

 13、歷史的重演是必然的。

 一個(gè)正常的企業(yè)或是項(xiàng)目,其運(yùn)作必須應(yīng)該是循環(huán)向上進(jìn)行的。而保障這種運(yùn)行的工作就是管理。而管理工作的主要內(nèi)容就是控制,包括控制循環(huán)的節(jié)奏——不能太快也不能太慢,控制發(fā)展的方向——只能向上不能向下,控制運(yùn)作的穩(wěn)定——不能大起大落或時(shí)聚時(shí)散等。
 而這一切,在這個(gè)例子中都看不到。

 在這個(gè)笑話的例子中,一切都是以開(kāi)發(fā)工作在驅(qū)動(dòng),這首先就是一個(gè)方向性錯(cuò)誤,產(chǎn)品是為用戶服務(wù)的,當(dāng)然應(yīng)該是以用戶和市場(chǎng)作為驅(qū)動(dòng),并且結(jié)合自身的能力最終 確定工作的重點(diǎn)。這一錯(cuò)誤折射出管理者對(duì)被管理的內(nèi)容很不了解,只好任由比較了解的程序員擺布——事實(shí)上他們除了技術(shù),并不會(huì)了解更多。

 一個(gè)管理者如果對(duì)自己所管理的內(nèi)容不了解,他就不可能管理得好。

 這是一件毫無(wú)疑問(wèn)的事,可是國(guó)內(nèi)的軟件業(yè)似乎總是不相信這一點(diǎn)。中國(guó)軟件業(yè)中流毒最深的謊言之一就是:

 管理者只要懂管理就可以,不需要懂技術(shù)。

其實(shí)這不過(guò)是那些無(wú)知無(wú)能無(wú)恥的管理者為了騙錢(qián)而編出來(lái)的,相信這句話的人必將付出金錢(qián)的代價(jià)。

 其次是質(zhì)量管理。基本的質(zhì)量管理常識(shí)告訴我們,每次循環(huán)結(jié)束前,最重的工作就是總結(jié)改進(jìn)。只有這樣才能保證循環(huán)運(yùn)作是向上發(fā)展,而不是失去控制地向下發(fā)展。 也只有有效的質(zhì)量管理,才能保證迭代過(guò)程是收斂發(fā)展,并最終達(dá)到目標(biāo)。但在這個(gè)例子中,這個(gè)部分顯然是缺失的——其中雖然有測(cè)試部門(mén),但是他們的作用僅僅 是質(zhì)量管理中的質(zhì)量檢測(cè)環(huán)節(jié),管理部分還是缺失的。

 然后是人力資源管理。軟件開(kāi)發(fā)是一項(xiàng)勞動(dòng)密集型的工作,雖然這是腦力勞動(dòng),但同樣意味著人在因素在其中占有決定性的地位。而例子中未改完BUG的程 序員拿到項(xiàng)目獎(jiǎng)金,而同樣辛苦工作的測(cè)試人員卻被拖欠薪資,除了表現(xiàn)出管理者對(duì)他們的工作內(nèi)容的不了解,以及對(duì)質(zhì)量管理工作的不重視以外,還表現(xiàn)出管理者 完全不會(huì)管人,這是一種謀殺團(tuán)隊(duì)的行為——謀殺一個(gè)團(tuán)隊(duì)遠(yuǎn)比建設(shè)要容易得多。

 最后,這個(gè)失敗的管理者把他的經(jīng)歷編成這個(gè)笑話,讓大家看到他被程序員們害得多慘,把程序員妖魔化為一群騙子。但只要稍懂管理的人簡(jiǎn)單分析一下就可以看出來(lái),只不過(guò)是這個(gè)人的無(wú)知和無(wú)能造成了他現(xiàn)在的結(jié)果,而把責(zé)任推給別人的行為更是表現(xiàn)出他的無(wú)恥。

 作為身居高位的管理者,如果連應(yīng)該承擔(dān)的責(zé)任都要推卸,他們還能勝任什么事情呢?

posted @ 2006-10-30 08:49 HUYU 閱讀(295) | 評(píng)論 (0)編輯 收藏

2006年10月13日 #

關(guān)注對(duì)TinyXML的應(yīng)用

關(guān)注對(duì)TinyXML的應(yīng)用
http://sourceforge.net/projects/tinyxml/

posted @ 2006-10-13 13:56 HUYU 閱讀(419) | 評(píng)論 (0)編輯 收藏

2006年10月4日 #

strlen & strcmp

unsigned int strlenW(const wchar_t *wcs)
{
?const wchar_t *eos = wcs;

?while (*eos)
???? ++eos;

?return eos-wcs;
}


int strcmpW(const wchar_t *pwc1, const wchar_t *pwc2)
{
?int ret = 0;

?while ( !(ret = *pwc1 - *pwc2) && *pwc2)
??++pwc1, ++pwc2;
?return ret;
}

posted @ 2006-10-04 00:02 HUYU 閱讀(395) | 評(píng)論 (0)編輯 收藏

如何識(shí)別字符串的編碼?

如果哪一天你的程序收到一段不明編碼的字符串,或者別人給了一個(gè)你看不懂的文本文件,你應(yīng)該如何去識(shí)別字符串的編碼呢?

一種是程序中用的方法,可以使用ICU之類的庫(kù)來(lái)幫你識(shí)別,如果你的字符串越長(zhǎng),它所能猜到的概率就越大。

另外一種方法是使用IE來(lái)幫助你查看。使用IE打開(kāi)不明編碼的文件,然后選擇Encoding,不停的切換編碼,基本上看起來(lái)像文字的時(shí)候,就是那個(gè)編碼了:).這個(gè)方法很簡(jiǎn)單,比較實(shí)用。

另外對(duì)于unicode的編碼,觀察其BOM,也有助于你去猜測(cè)編碼。
UTF-8: EF BB BF E6 B5 8B E8 AF 95 31 32 33 34
UTF-16: FF FE 4B 6D D5 8B 31 00 32 00 33 00 34 00
UTF-16 Big endian : FE FF 6D 4B 8B D5 00 31 00 32 00 33 00 34


最后附上兩個(gè)小工具,能幫你生成各種文字的字符和識(shí)別字符在不同code page下的編碼。just have fun

http://m.shnenglu.com/Files/sandy/encoding_tools.rar

posted @ 2006-10-04 00:01 HUYU 閱讀(1119) | 評(píng)論 (0)編輯 收藏

2006年9月4日 #

c++中的string用法(三)

     摘要: basic_string::max_size 返回string 能放的最大元素個(gè)數(shù)。(不同于capacity) size _ type max _ ...  閱讀全文

posted @ 2006-09-04 18:49 HUYU 閱讀(8425) | 評(píng)論 (0)編輯 收藏

僅列出標(biāo)題  下一頁(yè)
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美一区二区视频观看视频| 狠狠v欧美v日韩v亚洲ⅴ| 午夜日韩电影| 亚洲精品日韩精品| 亚洲欧美在线免费观看| 一区二区三欧美| 亚洲男人的天堂在线aⅴ视频| 一区二区三区 在线观看视频| 国产精品一区久久| 久久国内精品视频| 国产精品社区| 亚洲欧美日韩国产综合精品二区| 正在播放亚洲一区| 国产精品日韩在线观看| 夜夜嗨av一区二区三区网页| 亚洲一区精彩视频| 国产精品ⅴa在线观看h| 在线视频亚洲| 老司机67194精品线观看| 国产一区二区欧美| 久久久91精品国产一区二区三区| 免费视频一区| 亚洲一区二区三区乱码aⅴ| 欧美视频一区二| 亚洲午夜一区二区三区| 久久久另类综合| 一区二区高清| 在线观看视频日韩| 欧美日韩国产亚洲一区| 中文国产亚洲喷潮| 免费亚洲一区二区| 亚洲影视在线| 亚洲精品视频免费观看| 国产午夜久久| 国产精品免费在线| 欧美经典一区二区| 玖玖视频精品| 99re8这里有精品热视频免费 | 国产精品九色蝌蚪自拍| 久久久久久久国产| 韩日在线一区| 欧美日韩一区不卡| 亚洲精品一级| 亚洲网友自拍| 久久综合五月| 一本久久a久久免费精品不卡| 亚洲精选久久| 国产一区二区av| 亚洲国产精品一区二区www在线| 裸体歌舞表演一区二区| 亚洲大片av| 一区二区三区视频在线观看 | 欧美黑人在线观看| 蜜桃av噜噜一区| 亚洲国产第一页| 国产一区日韩一区| 国产精品豆花视频| 女人色偷偷aa久久天堂| 欧美在线黄色| 欧美高清自拍一区| 欧美激情中文字幕乱码免费| 欧美激情精品久久久久久变态| 久久一本综合频道| 欧美电影在线观看| 欧美日韩国产综合视频在线| 欧美日韩一本到| 亚洲综合999| 性8sex亚洲区入口| 免费欧美电影| 欧美成人午夜剧场免费观看| 欧美激情第三页| 亚洲私人影院| 奶水喷射视频一区| 国产精品美女999| 国产在线不卡| 91久久极品少妇xxxxⅹ软件| 99riav1国产精品视频| 亚洲天堂av在线免费| 久久久噜噜噜久久中文字幕色伊伊| 亚洲第一狼人社区| 一区二区av在线| 免费看亚洲片| 精品99视频| 亚洲欧美自拍偷拍| 亚洲大胆视频| 午夜宅男久久久| 欧美日韩国产综合久久| 国产在线观看一区| 欧美一级专区免费大片| 亚洲免费视频中文字幕| 国产视频精品网| 亚洲人成人99网站| 欧美一区二区三区喷汁尤物| 99re66热这里只有精品4| 亚洲欧美视频在线观看视频| 欧美精品尤物在线| 国产日韩欧美在线观看| 亚洲特级毛片| 亚洲午夜电影| 亚洲国产一区二区a毛片| 美女网站在线免费欧美精品| 激情综合久久| 亚洲经典视频在线观看| 欧美日韩精品免费| 在线午夜精品自拍| 亚洲日本在线观看| 国产精品v欧美精品v日本精品动漫 | 麻豆精品在线播放| 久久久精品999| 99视频精品全国免费| 女同一区二区| 欧美色欧美亚洲另类七区| 午夜一区二区三区在线观看| 亚洲视频大全| 精品成人一区| 亚洲一区二三| 99精品国产99久久久久久福利| 中文无字幕一区二区三区| 亚洲黄页一区| 亚洲视频网站在线观看| 国模大胆一区二区三区| 一区二区三区高清在线观看| 亚洲午夜电影| 欧美性猛片xxxx免费看久爱| 亚洲无限乱码一二三四麻| 亚洲在线观看免费视频| 在线亚洲欧美视频| 亚洲国产综合91精品麻豆| 久久精品一区二区三区不卡| 亚洲裸体视频| 午夜精品久久久久久99热| 一本色道久久综合精品竹菊| 亚洲精选大片| 欧美日韩成人在线观看| 亚洲精品麻豆| 亚洲性图久久| 欧美韩日一区二区| 亚洲国产精品欧美一二99| 91久久亚洲| 欧美视频一区在线| 99riav1国产精品视频| 亚洲人成网在线播放| 欧美h视频在线| 一区二区三区成人精品| 久久aⅴ国产紧身牛仔裤| 亚洲黄色小视频| 国产欧美日本| 美女999久久久精品视频| 欧美成人午夜激情视频| 一区二区三区四区精品| 久久午夜色播影院免费高清| 亚洲精品激情| 欧美一区二区三区日韩| 最新精品在线| 国产精品高潮粉嫩av| 久久亚洲欧美国产精品乐播| 亚洲视频在线观看一区| 亚洲毛片在线看| 久久国产精品电影| 玉米视频成人免费看| 国产三级精品在线不卡| 国产精品视频免费一区| 欧美日韩一区综合| 国产精品视频网址| 狠色狠色综合久久| 一区二区欧美激情| 欧美aa国产视频| 99re6热只有精品免费观看 | 99精品国产在热久久婷婷| 国产日韩欧美三区| 在线观看视频免费一区二区三区| 亚洲精品在线电影| 欧美激情亚洲精品| 一本色道久久综合狠狠躁篇怎么玩| 日韩午夜精品| 久久综合九色99| 国产精品九九| 1769国产精品| 欧美一区三区三区高中清蜜桃| 免费成人在线观看视频| 一区二区三区视频在线看| 免费观看在线综合色| 韩日欧美一区| 欧美在线free| 亚洲精品久久在线| 久久久久久久高潮| 国内精品视频在线播放| 久久成人久久爱| 久久久久久穴| 久久精品噜噜噜成人av农村| 激情五月综合色婷婷一区二区| 欧美一区国产一区| 欧美专区中文字幕| 国产一区美女| 久久精品99国产精品酒店日本| 亚洲性感激情| 国产日韩欧美综合精品| 久久久99免费视频| 亚洲欧美视频一区| 禁断一区二区三区在线|