C++函式的學習(二)
30 TranslateMessage
函式功能:該函式將虛擬鍵訊息轉換為字元訊息。字元訊息被寄送到呼叫執行緒的訊息佇列裡,當下一次執行緒呼叫函式GetMessage或PeekMessage時被讀出。
函式原型:
BOOLTranslateMessage(
CONSTMSG*lpMsg //message information
);
引數
IpMsg:指向含有訊息的MSG結構的指標,該結構裡含有用函式GetMessage或PeekMessage從呼叫執行緒的訊息佇列裡取得的訊息資訊。
返回值:如果訊息被轉換(即,字元訊息被寄送到呼叫執行緒的訊息佇列裡),返回非零值。如果訊息是WM_KEYDOWN,WM_KEYUPWM_SYSKEYDOWN或WM_SYSKEYUP,返回非零值,不考慮轉換。如果訊息沒被轉換(即,字元訊息沒被寄送到呼叫執行緒的訊息佇列裡),返回值是零。
備註:此函式不修改由引數IpMsg指向的訊息。
WM_KEYDOWN和WM_KEYUP組合產生一個WM_CHAR或WM_DEADCHAR訊息。
WM_SYSKEYDOWN和WM_SYSKEYUP組合產生一個WM_SYSCHAR或WM_SYSDEADCHAR訊息。TranslateMessage為那些由鍵盤驅動器對映為ASCll字元的鍵產生WM_CHAR訊息。
如果應用程式為其他用途處理虛擬鍵訊息,不應呼叫TranslateMessage。例如,如果件TranslateAccelerator返回一個非零值,應用程式不應呼叫TranslateMessage。
WindowsCE:WindowsCE不支援掃描碼或擴充套件鍵標誌,因此,不支援由TranslateMessage產生的WM_CHAR訊息中的IKeyData引數(IParam)取值16-24。
TranslateMessage只能用於轉換呼叫GetMessage或PeekMessage接收的訊息。
31 DispatchMessage
函式功能:該函式分發一個訊息給視窗程式。通常訊息從GetMessage函式獲得。訊息被分發到回撥函式(過程函式),作用是訊息傳遞給作業系統,然後作業系統去呼叫我們的回撥函式,也就是說我們在窗體的過程函式中處理訊息
函式原型:LONGDispatchMessage(CONST MSG*lpmsg);
引數:
lpmsg:指向含有訊息的MSG結構的指標。
返回值:返回值是視窗程式返回的值。儘管返回值的含義依賴於被排程的訊息,但返回值通常被忽略。
備註:MSG結構必須包含有效的訊息值。如果引數lpmsg指向一個WM_TIMER訊息,並且WM_TIMER訊息的引數IParam不為NULL,則呼叫IParam指向的函式,而不是呼叫視窗程式。
32 SSN::CA2W中各個字母的意思。。。把陣列轉化為
CW2A將寬字符集(Unicode)轉化為多字符集(ASCII)
CA2W就是反過來轉換了
注意要利用USES_CONVERSION提前進行宣告。
C: convert 轉換
W: wide 廣泛的
2: to 到
A ASCII; ASCII碼
33 extern 變數
extern可以置於變數或者函式前,以表示變數或者函式的定義在別的檔案中,提示編譯器遇到此變數和函式時在其他模組中尋找其定義。另外,extern也可用來進行連結指定。
在一個原始檔裡定義了一個陣列:char a[6];
在另外一個檔案裡用下列語句進行了宣告:extern char *a;
請問,這樣可以嗎?
答案與分析:
1)、不可以,程式執行時會告訴你非法訪問。原因在於,指向型別T的指標並不等價於型別T的陣列。extern char *a宣告的是一個指標變數而不是字元陣列,因此與實際的定義不同,從而造成執行時非法訪問。應該將宣告改為extern char a[ ]。
2)、例子分析如下,如果a[] = "abcd",則外部變數a=0x12345678 (陣列的起始地址),而*a是重新定義了一個指標變數a的地址可能是0x87654321,直接使用*a是錯誤的.
3)、這提示我們,在使用extern時候要嚴格對應宣告時的格式,在實際程式設計中,這樣的錯誤屢見不鮮。
4)、extern用在變數宣告中常常有這樣一個作用,你在*.c檔案中聲明瞭一個全域性的變數,這個全域性的變數如果要被引用,就放在*.h中並用extern來宣告。
34 把陣列定義成結構體型別。
把一個班的學生姓名和成績存放到一個結構陣列中,尋找和輸出最高分者。
#include<iostream>
#include<string>
using namespace std;
#define MAX 100
struct student
{
string name;
float score;
};
void main()
{
student stu[MAX];
int max=-1,n;
cout<<"請輸入班級人數:";
int num;
cin>>num;
for(int i=1;i<=num;i++)
{
cout<<endl<<"請輸入第"<<i<<"個人的姓名和分數:"<<endl;
cin>>stu[i-1].name>>stu[i-1].score;
if(max<stu[i-1].score)
{max=stu[i-1].score;n=i-1;}
}
cout<<"分數最高者為:"<<endl;
cout<<stu[n].name<<" 分數為: "<<stu[n].score<<endl;
}
35 char a[MAX_PATH]
#define MAX_PATH 256 巨集定義,定義陣列的大小;
36 ZeroMemory
ZeroMemory,是美國微軟公司的軟體開發包SDK中的一個巨集。其作用,是用0來填充一塊記憶體區域。
用法
宣告
void ZeroMemory( PVOID Destination,SIZE_T Length);
引數
Destination :指向一塊準備用0來填充的記憶體區域的開始地址。
Length :準備用0來填充的記憶體區域的大小,按位元組來計算。
返回值
無
作用
ZeroMemory只是將指定的記憶體塊清零。
使用結構前清零,而不讓結構的成員數值具有不確定性,是一個好的程式設計習慣。
37 _tcsncpy_s的用法;
errno_t strncpy_s(
char *strDest,
size_t numberOfElements,
const char *strSource,
size_t count
);
strDest:Destination string.:目標字串。
numberOfElements:The size of the destination string, incharacters.:目的地的大小的字串,在字元。
strSource:Source string.源字串。
Count:Number of characters to be copied, or _TRUNCATE.要複製的字元數,或_TRUNCATE
Locale:The locale to use.:語言環境使用。
38
typedefstruct _KEY_INFO_{
INT nVKcode; // 鍵值虛擬碼例:VK_INSERT
TCHAR szVKName[SSN_NAMELEN]; // 鍵字串例:VK_PAD_INSERT
TCHAR szVKDescID[SSN_NAMELEN]; // 鍵漢字描述字串ID;因為資源在文字檔案裡所以ID也是字串型別
TCHAR szVKDesc[SSN_NAMELEN]; // 鍵漢字描述字串例:小鍵盤零
_KEY_INFO_()
{nVKcode=0;ZeroMemory(szVKName, sizeof(szVKName));ZeroMemory(szVKDescID,sizeof(szVKDescID));/*ZeroMemory(szVKDesc,sizeof(szVKDesc));*/};
_KEY_INFO_(INT code, const TCHAR*keyName, const TCHAR *keyDescID/*, constTCHAR *keyDesc=NULL*/)
{nVKcode=code;_tcsncpy_s(szVKName, _countof(szVKName),keyName, _TRUNCATE); _tcsncpy_s(szVKDescID,_countof(szVKDescID), keyDescID, _TRUNCATE); /*_tcsncpy_s(szVKDesc, _countof(szVKDesc), keyDesc,_TRUNCATE);*/};
}SSN_KEY_INFO, *PSSN_KEY_INFO;
第一個沒引數的叫預設建構函式第二個叫帶引數的建構函式
_KEY_INFO_()
{nVKcode=0;ZeroMemory(szVKName, sizeof(szVKName));ZeroMemory(szVKDescID,sizeof(szVKDescID));/*ZeroMemory(szVKDesc,sizeof(szVKDesc));*/};
_KEY_INFO_(INT code, const TCHAR*keyName, const TCHAR *keyDescID/*, constTCHAR *keyDesc=NULL*/)
{nVKcode=code;_tcsncpy_s(szVKName, _countof(szVKName),keyName, _TRUNCATE); _tcsncpy_s(szVKDescID,_countof(szVKDescID), keyDescID, _TRUNCATE); /*_tcsncpy_s(szVKDesc, _countof(szVKDesc), keyDesc,_TRUNCATE);*/};
的過程,如同給一個變數先賦一個預設值,然後在執行以下程式;
39 求字串的長度
#define _countof(_Array) (sizeof(_Array)/ sizeof(_Array[0]))
40 size_t
size_t 型別定義在cstddef標頭檔案中,該檔案是C標準庫的標頭檔案stddef.h的C++版。它是一個與機器相關的unsigned型別,其大小足以保證儲存記憶體中物件的大小。
41
結構體內部可以定義函式,來表示結構體的特點。
42 GetKeyState
函式功能:該函式檢取指定虛擬鍵的狀態。該狀態指定此鍵是UP狀態,DOWN狀態,還是被觸發的(開關每次按下此鍵時進行切換)。
函式原型:SHORTGetKeyState(int nVirtKey);
函式:
nVrtKey:定義一虛擬鍵。若要求的虛擬鍵是字母或數字(A~Z,a~z或0~9),nVirtKey必須被置為相應字元的ASCII碼值,對於其他的鍵,nVirtKey必須是一虛擬鍵碼。若使用非英語鍵盤佈局,則取值在ASCIIa~z和0~9的虛擬鍵被用於定義絕大多數的字元鍵。例如,對於德語鍵盤格式,值為ASCII0(OX4F)的虛擬鍵指的是"0"鍵,而VK_OEM_1指"帶變音的0鍵"
返回值:返回值給出了給定虛擬鍵的狀態,狀態如下:
若高序位為1,則鍵處於DOWN狀態,否則為UP狀態。
若低序位為1,則鍵被觸發。例如CAPSLOCK鍵,被找開時將被觸發。若低序位置為0,則鍵被關閉,且不被觸發。觸發鍵在鍵盤上的指示燈,當鍵被觸發時即亮,鍵不被觸發時即滅。
備註:當給定執行緒從它的訊息佇列中讀鍵訊息時,該函式返回的鍵狀態發生改變。該狀態並不反映與硬體相關的中斷級的狀態。使用GetAsyncKeyState可獲取這一資訊。
43 KBDLLHOOKSTRUCT 結構體的用法
Private Type KBDLLHOOKSTRUCT'這個是低階鍵盤鉤子的索引值
vkCode As Long '虛擬按鍵碼(1--254)
scanCode As Long '硬體按鍵掃描碼
flags As Long '鍵按下:128 擡起:0
time As Long '訊息時間戳間
dwExtraInfo As Long '額外資訊
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
}KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
44 multimap
multimap::multimap(STL/CLR)
first
last
End of range to insert.(結束的範圍來插入。)
pred
right
typedef multimap<_Kty, _Ty, _Pr, _Alloc> _Myt;
45 map Class
template<
class Key,
class Type,
class Traits = less<Key>,
class Allocator=allocator<pair <const Key, Type>>
>
class map
Key
Type
Traits
型別,提供了一個函式物件,可以比較兩個元素值作為排序鍵,以確定其相對順序在地圖上。此引數是可選的,二元謂詞少<KEY>是預設值。
Allocator
型別表示儲存分配器物件封裝了有關地圖的分配和釋放記憶體的詳細資訊。此引數是可選的,預設值是分配器<的一雙<constKey, TYPE>>。
Map以按鍵/數值對的形式儲存資料,和陣列非常相似,在陣列中存在的索引,它們本身也是物件。
Map的介面
Map---實現Map
Map.Entry--Map的內部類,描述Map中的按鍵/數值對。
SortedMap---擴充套件Map,使按鍵保持升序排列
46 #pragma
在所有的預處理指令中,#Pragma指令可能是最複雜的了,它的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。#pragma指令對每個編譯器給出了一個方法,在保持與C和C++語言完全相容的情況下,給出主機或作業系統專有的特徵。依據定義,編譯指示是機器或作業系統專有的,且對於每個編譯器都是不同的。
一般格式
其格式一般為: #pragma Para。其中Para 為引數,下面來看一些常用的引數。
(1)message引數
Message 引數能夠在編譯資訊輸出視窗中輸出相應的資訊,這對於原始碼資訊的控制是非常重要的。其使用方法為:
#pragma message(“訊息文字”)
當編譯器遇到這條指令時就在編譯輸出視窗中將訊息文字打印出來。
當我們在程式中定義了許多巨集來控制原始碼版本的時候,我們自己有可能都會忘記有沒有正確的設定這些巨集,此時我們可以用這條指令在編譯的時候就進行檢查。假設我們希望判斷自己有沒有在原始碼的什麼地方定義了_X86這個巨集可以用下面的方法
#ifdef _X86
#pragma message(“_X86 macro activated!”)
#endif
當我們定義了_X86這個巨集以後,應用程式在編譯時就會在編譯輸出窗口裡顯示“_X86macro activated!”。我們就不會因為不記得自己定義的一些特定的巨集而抓耳撓腮了。
(2)code_seg
另一個使用得比較多的pragma引數是code_seg。格式如:
#pragma code_seg( ["section-name"[,"section-class"]] )
它能夠設定程式中函式程式碼存放的程式碼段,當我們開發驅動程式的時候就會使用到它。
(3)#pragmaonce
(比較常用)
只要在標頭檔案的最開始加入這條指令就能夠保證標頭檔案被編譯一次,這條指令實際上在VC6中就已經有了,但是考慮到相容性並沒有太多的使用它。
#pragma once是編譯相關,就是說這個編譯系統上能用,但在其他編譯系統不一定可以,也就是說移植性差,不過現在基本上已經是每個編譯器都有這個定義了。
#ifndef,#define,#endif這個是C++語言相關,這是C++語言中的巨集定義,通過巨集定義避免檔案多次編譯。所以在所有支援C++語言的編譯器上都是有效的,如果寫的程式要跨平臺,最好使用這種方式。
(4)#pragmahdrstop
#pragma hdrstop表示預編譯標頭檔案到此為止,後面的標頭檔案不進行預編譯。BCB可以預編譯標頭檔案以加快連結的速度,但如果所有標頭檔案都進行預編譯又可能佔太多磁碟空間,所以使用這個選項排除一些標頭檔案。
有時單元之間有依賴關係,比如單元A依賴單元B,所以單元B要先於單元A編譯。你可以用#pragma startup指定編譯優先順序,如果使用了#pragma package(smart_init) ,BCB就會根據優先順序的大小先後編譯。
(5)#pragmaresource
#pragma resource "*.dfm"表示把*.dfm檔案中的資源加入工程。*.dfm中包括窗體外觀的定義。
(6)#pragmawarning
#pragma warning( disable : 4507 34; once : 4385;error : 164 )
等價於:
#pragma warning(disable:4507 34) // 不顯示4507和34號警告資訊
#pragma warning(once:4385) // 4385號警告資訊僅報告一次
#pragma warning(error:164) // 把164號警告資訊作為一個錯誤。
同時這個pragma warning 也支援如下格式:
#pragma warning( push [ ,n ] )
#pragma warning( pop )
這裡n代表一個警告等級(1---4)。
#pragma warning( push )儲存所有警告資訊的現有的警告狀態。
#pragma warning( push, n)儲存所有警告資訊的現有的警告狀態,並且把全域性警告等級設定為n。
#pragma warning( pop )向棧中彈出最後一個警告資訊,
在入棧和出棧之間所作的一切改動取消。例如:
#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
//.......
#pragma warning( pop )
在這段程式碼的最後,重新儲存所有的警告資訊(包括4705,4706和4707)。
(7)pragmacomment
pragma comment(...)
該指令將一個註釋記錄放入一個物件檔案或可執行檔案中。
常用的lib關鍵字,可以幫我們連入一個庫檔案。
每個編譯程式可以用#pragma指令啟用或終止該編譯程式支援的一些編譯功能。例如,對迴圈優化功能:
#pragma loop_opt(on) // 啟用
#pragma loop_opt(off) // 終止
有時,程式中會有些函式會使編譯器發出你熟知而想忽略的警告,如“Parameter xxx is never used in function xxx”,可以這樣:
#pragma warn —100 // Turn off the warning messagefor warning #100
int insert_record(REC *r)
{ /* function body */ }
#pragma warn +100 // Turn the warning message forwarning #100 back on
函式會產生一條有唯一特徵碼100的警告資訊,如此可暫時終止該警告。
每個編譯器對#pragma的實現不同,在一個編譯器中有效在別的編譯器中幾乎無效。可從編譯器的文件中檢視。
#pragma pack(n)和#pragma pop()
struct sample
{
char a;
double b;
};
當sample結構沒有加#pragma pack(n)的時候,sample按最大的成員那個對齊;
(所謂的對齊是指對齊數為n時,對每個成員進行對齊,既如果成員a的大小小於n則將a擴大到n個大小;
如果a的大小大於n則使用a的大小;)所以上面那個結構的大小為16位元組.
當sample結構加#pragma pack(1)的時候,sizeof(sample)=9位元組;無空位元組。
(另注:當n大於sample結構的最大成員的大小時,n取最大成員的大小。
所以當n越大時,結構的速度越快,大小越大;反之則)
#pragma pop()就是取消#pragma pack(n)的意思了,也就是說接下來的結構不用#pragma pack(n)
#pragma comment( comment-type,["commentstring"] )
comment-type是一個預定義的識別符號,指定註釋的型別,應該是compiler,exestr,lib,linker之一。
commentstring是一個提供為comment-type提供附加資訊的字串。
註釋型別:
1、compiler:
放置編譯器的版本或者名字到一個物件檔案,該選項是被linker忽略的。
2、exestr:
在以後的版本將被取消。
3、lib:
放置一個庫搜尋記錄到物件檔案中,這個型別應該是和commentstring(指定你要Linker搜尋的lib的名稱和路徑)這個庫的名字放在Object檔案的預設庫搜尋記錄的後面,linker搜尋這個這個庫就像你在命令列輸入這個命令一樣。你可以在一個原始檔中設定多個庫記錄,它們在object檔案中的順序和在原始檔中的順序一樣。如果預設庫和附加庫的次序是需要區別的,使用Z編譯開關是防止預設庫放到object模組。
4、linker:
linker:指定一個連線選項,這樣就不用在命令列輸入或者在開發環境中設定了。
只有下面的linker選項能被傳給Linker.
/DEFAULTLIB,/EXPORT,/INCLUDE,/MANIFESTDEPENDENCY, /MERGE,/SECTION
(1) /DEFAULTLIB:library
/DEFAULTLIB 選項將一個 library 新增到 LINK 在解析引用時搜尋的庫列表。用 /DEFAULTLIB指定的庫在命令列上指定的庫之後和 .obj 檔案中指定的預設庫之前被搜尋。忽略所有預設庫 (/NODEFAULTLIB) 選項重寫 /DEFAULTLIB:library。如果在兩者中指定了相同的library 名稱,忽略庫 (/NODEFAULTLIB:library) 選項將重寫/DEFAULTLIB:library。
(2)/EXPORT:entryname[,@ordinal[,NONAME]][,DATA]
使用該選項,可以從程式匯出函式,以便其他程式可以呼叫該函式。也可以匯出資料。通常在 DLL 中定義匯出。entryname是呼叫程式要使用的函式或資料項的名稱。ordinal 在匯出表中指定範圍在 1 至 65,535 的索引;如果沒有指定 ordinal,則 LINK 將分配一個。NONAME關鍵字只將函式匯出為序號,沒有 entryname。
DATA 關鍵字指定匯出項為資料項。客戶程式中的資料項必須用 extern __declspec(dllimport)來宣告。
有三種匯出定義的方法,按照建議的使用順序依次為:
原始碼中的 __declspec(dllexport).def 檔案中的 EXPORTS 語句LINK 命令中的 /EXPORT 規範所有這三種方法可以用在同一個程式中。LINK在生成包含匯出的程式時還建立匯入庫,除非生成中使用了 .exp 檔案。
LINK 使用識別符號的修飾形式。編譯器在建立 .obj 檔案時修飾識別符號。如果 entryname以其未修飾的形式指定給連結器(與其在原始碼中一樣),則 LINK 將試圖匹配該名稱。如果無法找到唯一的匹配名稱,則 LINK 發出錯誤資訊。當需要將識別符號指定給連結器時,請使用 Dumpbin 工具獲取該識別符號的修飾名形式。
#pragmacomment(linker,"/SECTION:shared,RWS")
這些字句的解釋:
第一個#pragma敘述建立資料段,這裡命名為shared。您可以將這段命名為任何一個您喜歡的名字。在這裡的#pragma敘述之後的所有初始化了的變數都放在shared資料段中。第二個#pragma敘述標示段的結束。對變數進行專門的初始化是很重要的,否則編譯器將把它們放在普通的未初始化資料段中而不是放在shared中。
連結器必須知道有一個「shared」共享資料段。在「Project Settings」對話方塊選擇「Link」頁面卷標。選中「STRLIB」時在「Project Options」欄位(在Release和Debug設定中均可),包含下面的連結敘述:
/SECTION:shared,RWS
字母RWS表示段具有讀、寫和共享屬性。或者,您也可以直接用DLL原始碼指定連結選項,就像我們在STRLIB.C那樣:
#pragmacomment(linker,"/SECTION:shared,RWS")
(3)/INCLUDE:symbol
/INCLUDE 選項通知連結器將指定的符號新增到符號表。
若要指定多個符號,請在符號名稱之間鍵入逗號 (,)、分號 (;) 或空格。在命令列上,對每個符號指定一次 /INCLUDE:symbol。
連結器通過將包含符號定義的物件新增到程式來解析 symbol。該功能對於添包含不會連結到程式的庫物件非常有用。用該選項指定符號將通過 /OPT:REF 重寫該符號的移除。
我們經常用到的是#pragma comment(lib,"*.lib")這類的。#pragma comment(lib,"Ws2_32.lib")表示連結Ws2_32.lib這個庫。和在工程設定裡寫上鍊入Ws2_32.lib的效果一樣,不過這種方法寫的程式別人在使用你的程式碼的時候就不用再設定工程settings了
(8)#pragmadata_seg
#pragma data_seg介紹
用#pragma data_seg建立一個新的資料段並定義共享資料,其具體格式為:
#pragma data_seg ("shareddata")
HWND sharedwnd=NULL;//共享資料
#pragma data_seg()
-----------------------------------------------------------------
1,#pragmadata_seg()一般用於DLL中。也就是說,在DLL中定義一個共享的有名字的資料段。最關鍵的是:這個資料段中的全域性變數可以被多個程序共享,否則多個程序之間無法共享DLL中的全域性變數。
2,共享資料必須初始化,否則微軟編譯器會把沒有初始化的資料放到.BSS段中,從而導致多個程序之間的共享行為失敗。例如,
#pragma data_seg("MyData")
int g_Value; // Note that the global is notinitialized.
#pragma data_seg()
DLL提供兩個介面函式:
int GetValue()
{
return g_Value;
}
void SetValue(int n)
{
g_Value = n;
}
然後啟動兩個程序A和B,A和B都呼叫了這個DLL,假如A呼叫了SetValue(5); B接著呼叫int m = GetValue(); 那麼m的值不一定是5,而是一個未定義的值。因為DLL中的全域性資料對於每一個呼叫它的程序而言,是私有的,不能共享的。假如你對g_Value進行了初始化,那麼g_Value就一定會被放進MyData段中。換句話說,如果A呼叫了SetValue(5); B接著呼叫int m = GetValue(); 那麼m的值就一定是5,這就實現了跨程序之間的資料通訊。
47
#pragma data_seg( ".mysec ")
HWND g_hwnd=NULL;
#pragma data_seg()
#pragma comment(linker,"/section:mysec,RWS ")
編譯成功後,我用dumpbin/headers 看了一下,改不成Shared屬性。
我用的是vc++.net 是不是編譯器那裡還需要設定呢?
謝謝
兩個改錯方案:
1、
#pragma data_seg( ".mysec ")
HWND g_hwnd=NULL;
#pragma data_seg()
#pragma comment(linker,"/section:.mysec,RWS ")
2、
#pragma data_seg( "mysec ")
HWND g_hwnd=NULL;
#pragma data_seg()
#pragma comment(linker,"/section:mysec,RWS ")
都行。
48 memset
將s所指向的某一塊記憶體中的每個位元組的內容全部設定為ch指定的ASCII值, 塊的大小由第三個引數指定,這個函式通常為新申請的記憶體做初始化工作, 其返回值為指向S的指標。
void *memset(void *s, int ch, size_t n);
函式解釋:將s中前n個位元組替換為ch並返回s;
memset:作用是在一段記憶體塊中填充某個給定的值,它是對較大的結構體或陣列進行清零操作的一種最快方法。
49 _tcscpy_s
TCHAR.H routine |
_UNICODE & _MBCS not defined |
_MBCS defined |
_UNICODE defined |
_tcscpy_s |
strcpy_s |
_mbscpy_s |
wcscpy_s |
複製一個字串。這些都是_mbscpy與wcscpy,STRCPY的安全性增強版本,在CRT的安全功能描述。
strcpy
原型宣告:extern char *strcpy(char *dest,const char *src);
功能:把從src地址開始且含有NULL結束符的字串賦值到以dest開始的地址空間
說明:src和dest所指記憶體區域不可以重疊且dest必須有足夠的空間來容納src的字串。 返回指向dest的指標。
_tcscpy_s
errno_t strcpy_s(
char *strDestination,
size_t numberOfElements,
const char *strSource
);
strDestination
Location of destination string buffer:目的地的位置字串緩衝區;
numberOfElements
strSource
char *p=NULL;
try {
p=new char[128];
}
catch(...) //抓所有的異常 {
//異常處理
}
要防止因為異常產生的記憶體洩漏,可以使用智慧指標,也可以用
__try
{
}
__finally
{
}《Windows核心程式設計》一書第23~25章是很好的參考資料。
try,catch,throw:
try包含你要防護的程式碼 ,稱為防護塊. 防護塊如果出現異常,會自動生成異常物件並丟擲.
catch捕捉特定的異常,並在其中進行適當處理.
throw可以直接丟擲/產生異常,導致控制流程轉到catch塊.
重要觀點: C++中異常是用物件來表示的,稱為異常物件.
基本格式:
try{ your code; }
catch(T1t1) //T1可以是任意型別,int,char,CException...
{/*T1指定了你要捕捉的異常的型別,t1指定了異常物件的名稱,當有異常丟擲,異常物件將被複制到t1 中,這樣你就可以在本處理塊中使用該物件,獲取相關資訊,進行適當處理. 處理程式碼;*/}
catch(T2*pt1)
//上面的catch是值傳遞,這裡使用指標傳遞.
{ 處理程式碼; }
catch(...)
//...是捕捉任意型別的異常.
{ 處理程式碼; }
//其他程式碼;
/*某個catch執行完,就跳轉到這裡繼續執行. 在沒有使用C++異常處理的情況下,如果在此之前出現異常,則//這裡的其他程式碼不會被執行,從而造成問題.請考慮在這裡放置: delete pobj1; 如果不使用用try,catch機制,記憶體洩漏是必然的, 因為出現問題後,執行流程無法跳轉到這裡. */
/*說明: try{}之後可以跟任意個catch塊. 發生異常後,會生成臨時的異常物件,進行一些自動處理之後,程式 流程跳轉到後面的catch(),逐個檢查這些catch(),如果與catch() 中指定的型別一致,則將物件拷貝給catch引數中的物件, 接著執行該catch塊中的程式碼,然後跳過其他所有剩下的catch, 繼續執行後續的程式碼.
上面所說的自動處理指的是堆疊回退,說白了就是為函式中的區域性物件呼叫解構函式,保證這些區域性物件行為良好. */
catch()的順序通常按照:從特殊到一般的順序: catch(Tsub o){} catch(Tbaseo){} catch(...){} 如果第一個catch為catch(Tbase){},則它將捕捉其所有派生類的異常物件. 如果第一個catch為catch(...){},則其後的所有catch永遠不可能被執行.
重新丟擲異常: 從上面的處理機制可以看到,只有一個catch可能被執行, 如果一個catch被執行,其他後續的catch就會被跳過了. 有時候一個catch中可能無法完成異常的全部處理,需要將異常提交給更高的層,以期望得到處理.重新丟擲異常實現了這種可能性. 語法: throw ; 空的throw語句,只能在catch中使用. 它重新丟擲異常物件,其外層的catch可能可以捕捉這個重新丟擲的異常並做適當處理.
51 TCHAR字串操作函式:
_tcslen(str) 獲得字串長度
_tcsrchr(str, L'\\') 反向搜尋獲得最後一個TCHAR的位置
_stprintf(TCHAR *buffer,const TCHAR *format[,argument] ... )獲得一個格式化字串
_tcsdup 給一個指標分配源字串大小的記憶體並從源字串copy值
_tcstok 按標記將字串拆分
tcscpy拷貝字串
Containsstrings returned from the IShellFolder interface methods.
包含從IShellFolder介面的方法返回的字串。
typedef struct _STRRET {
UINT uType;
union {
LPWSTR pOleStr;
UINT uOffset;
CHAR cStr[MAX_PATH];
};
} STRRET, *LPSTRRET;
Members
uType
Type: UINT
一個值,指定所需的格式字串。這可以是下列值之一。
STRRET_CSTR
該字串被返回在CSTR成員。
STRRET_OFFSET
The uOffset member value indicates the number ofbytes from the beginning of the item identifier list where the string islocated.
從開始的專案識別符號列表的字串位於uOffset成員值表示的位元組數。
STRRET_WSTR
字串是pOleStr成員中指定的地址。
pOleStr
Type: LPWSTR
字串的指標。這必須與CoTaskMemAlloc來分配記憶體。它是呼叫應用程式的責任與CoTaskMemFree釋放記憶體,當它不再需要。
uOffset
Type: UINT
偏移到專案識別符號列表。
cStr
Type: CHAR[MAX_PATH]
53 空語句
只有分號“;”組成的語句稱為空語句。
空語句是什麼也不執行的語句。在程式中空語句可用來作空迴圈體。
例如 while(getchar()!='\n');
本語句的功能是,只要從鍵盤輸入的字元不是回車則重新輸入。這裡的迴圈體為空語句
空語句僅由一個分號組成,不進行任何操作。一般用於語法上要求有一條語句但實際沒有任何操作的場合。例如:
for(i=1;i<10;i++); //空語句,起延時作用。。。
他是一個完整的迴圈結構,在多數情況下用於時間等待。
54 LPCTSTR型別:
LP:long型指標,這是為了相容Windows 3.1等16位作業系統遺留下來的,在win32中以及其他的32為作業系統中, long指標和near指標及far修飾符都是為了相容的作用。沒有實際意義。
C:常量;
T:和_T含義一樣,應該是UNICODE型;
STR:字串
55 CreateDirectory
呼叫這個成員函式建立一個連線的伺服器上的目錄。
BOOL CreateDirectory(
LPCTSTRpstrDirName
);
pstrDirName
A pointer to a string containing the name of thedirectory to create.
一個指標指向字串包含的目錄的名稱來建立。
56 assert() 函式用法
assert巨集的原型定義在assert.h中,其作用是如果它的條件返回錯誤,則終止程式執行.
原型定義:
1 |
#include "assert.h" |
|
2 |
void assert( int expression ); |
assert的作用是現計算表示式 expression ,如果其值為假(即為0),那麼它先向stderr列印一條出錯資訊,然後通過呼叫 abort 來終止程式執行。
57 empty
hash_map::empty
bool empty( ) const;
true if the hash_map is empty; false if the hash_map is nonempty.
真實的,如果hash_map是空的;hash_map是假的,如果非空。
58
tstring szAppPath =GetAppPath();
::CreateDirectory(strRet.c_str(),NULL);
strRet.size()
寫相應的變數. 後邊可以自動彈出一些函式;
這些函式是在其他類中定義的,再該檔案中宣告類該類的物件。則就可以應用該類的成員函式。
:: 這個符號是用於全域性變數的;
class B;//宣告類B
CTTSManager g_TTSManager;
CTTSManager 是類宣告物件
59 c_str() 的用法
語法:
constchar *c_str();
c_str()函式返回一個指向正規C字串的指標, 內容與本string串相同.
這是為了與c語言相容,在c語言中沒有string型別,故必須通過string類物件的成員函式c_str()把string 物件轉換成c中的字串樣式。
注意:一定要使用strcpy()函式等來操作方法c_str()返回的指標
比如:最好不要這樣:
char*c;
strings="1234";
c = s.c_str(); //c最後指向的內容是垃圾,因為s物件被析構,其內容被處理
應該這樣用:
char c[20];
string s="1234";
strcpy(c,s.c_str());
這樣才不會出錯,c_str()返回的是一個臨時指標,不能對其進行操作
再舉個例子
c_str()以 char* 形式傳回 string 內含字串
如果一個函式要求char*引數,可以使用c_str()方法:
strings = "Hello World!";
printf("%s",s.c_str()); //輸出 "HelloWorld!"