1.vector和string優(yōu)先于動態(tài)分配的數(shù)組。
2.使用reserve來避免不必要的重新分配
關(guān)于stl容器會自動增長以便容納下你放入其中的數(shù)據(jù),只要沒有超過它們的最大限制就可以。對于vector和string,增長過程是這樣實現(xiàn)的:每當(dāng)需要更多空間時,就調(diào)用與realloc類似的操作。這一類似于relloc的操作分為如下4部分:
(1)分配一塊大小為當(dāng)前容量的某個倍數(shù)的新內(nèi)存。在大多數(shù)實現(xiàn)中,vector和string的容量每次以2的倍數(shù)增長,即每當(dāng)容器需要擴(kuò)張時,它們的容量即加倍。
(2)把容器的所有元素從舊的內(nèi)存復(fù)制到新的內(nèi)存中。
(3)析構(gòu)掉舊內(nèi)存中的元素
(4)釋放舊內(nèi)存
reserve成員函數(shù)能使你把重新分配的次數(shù)減少到最低限度,從而避免了重新分配和指針迭代器引用失效帶來的開銷。
簡單概括一下四個相互關(guān)聯(lián)、但有時會被混淆的成員函數(shù)。在標(biāo)準(zhǔn)容器中,只有vector和string提供了所有這四個函數(shù):
(1)size() 告訴你容器中有多少個元素,它不會告訴你該容器為自己所包含的元素分配了多少內(nèi)存。
(2)capacity()告訴你容器利用已經(jīng)分配的內(nèi)存可以容納多少元素。這是容器所能容納的元素總數(shù),而不是它還能容納多少個元素。如果你想知道一個vector有多少未被使用的內(nèi)存,就得從capacity()中減去size()。如果size和capacity返回同樣的值,就說明容器中不再有剩余空間了,因此下一個插入操作(push_back)將導(dǎo)致上面所提到的重新分配過程。
(3)resize(xx)強迫容器改變到包含n個元素的狀態(tài)。在調(diào)用resize之后,size將返回n。如果n比當(dāng)前的大?。╯ize)要小,則容器尾部的元素將會被析構(gòu)掉。如果n比當(dāng)前的大小要大,則通過默認(rèn)構(gòu)造函數(shù)創(chuàng)建的新元素將被添加到容器的末尾。如果n比當(dāng)前的容量要大,那么在添加元素之前,將先重新分配內(nèi)存。
(4)reserve(xx)強迫容器把它的容量變?yōu)橹辽偈莕,前提是n不小于當(dāng)前的大小。這通常會導(dǎo)致重新分配,因為容量需要增加。(如果n比當(dāng)前的容量小,則vector什么也不做)
因此,避免重新分配的關(guān)鍵在于,盡早的只用reserve,把容器的容量設(shè)為足夠大的值,最好是在容器剛被構(gòu)造出來之后就使用reserve。
3.注意string實現(xiàn)的多樣性
4.了解如何把vector和string數(shù)據(jù)傳給舊的API
5.使用“swap技巧”除去多余的容量。
6.避免使用vector<bool>
vector<bool>不是一個stl容器,也不存儲bool。在一個典型的實現(xiàn)中,儲存在vector中的每個bool僅占一個二進(jìn)制位,一個8位的字節(jié)可容納8g個“bool”。在內(nèi)部vector<bool>使用了與位域一樣的思想,來表示它所存儲的那些bool;實際上只是假裝存儲了這些bool。
vector<bool>不完全滿足STL容器的要求;你最好不要使用它;你可以使用deque<bool>和bitset來替代它,這兩個數(shù)據(jù)結(jié)構(gòu)幾乎能做vector<bool>所能做的一切事情。
慎重選擇容器類型
標(biāo)準(zhǔn)序列容器:vector string deque list
標(biāo)準(zhǔn)關(guān)聯(lián)容器 : set multiset map multimap
非標(biāo)準(zhǔn)序列容器: slist rope. slist 是一個單向鏈表,rope 本質(zhì)上市一個“重型”string
非標(biāo)準(zhǔn)的關(guān)聯(lián)容器 hash_set hash_nultiset hash_map hash_multimap vector 作為string的替代。 vector 作為標(biāo)準(zhǔn)關(guān)聯(lián)容器的替代
幾種標(biāo)準(zhǔn)的非STL容器 包括 數(shù)組、bitset valarray stack queue 和 priority_queue
容器可分類為 連續(xù)內(nèi)存容器和基于節(jié)點的容器
連續(xù)內(nèi)存容器把它的元素存放在一塊或多塊(動態(tài)分配的)內(nèi)存中,每塊內(nèi)存中存有多個元素。當(dāng)有新元素插入或已有的元素被刪除時,同一內(nèi)存塊中的其他元素要向前或向后移動,以便為新元素讓出空間,或者填充被刪除元素所留下的空隙。
基于節(jié)點的容器在每一個(動態(tài)分配的)內(nèi)存塊中只存放一個元素。容器中元素的插入或刪除只影響到指向節(jié)點的指針,而不影響節(jié)點本身的內(nèi)容,所以當(dāng)有插入或刪除操作時,元素的值不需要移動。
你是否需要在容器的任意位置插入新元素?如果需要,就選擇序列容器;關(guān)聯(lián)容器是不行的。
你是否關(guān)心容器中的元素師排序的?如果不關(guān)心,則哈希容器室一個可行的選擇方案;否則,你要避免哈希容器。
容器中數(shù)據(jù)的布局是否需要和C兼容?如果需要兼容,就只能選擇vector。
元素的查找速度是否是關(guān)鍵的考慮因素?如果是,就要考慮哈希容器、排序的vector和標(biāo)準(zhǔn)關(guān)聯(lián)容器——或許這就是優(yōu)先順序。
確保容器中的對象拷貝正確而高效
調(diào)用empty而不是檢查size()是否為 0
理由很簡單:empty對所有的標(biāo)準(zhǔn)容器都是常數(shù)時間操作,而對一些list實現(xiàn),size耗費線性時間。由于list所獨有的鏈接操作。
區(qū)間成員函數(shù)優(yōu)先于與之對應(yīng)的單元素成員函數(shù)。
如果容器中包含了通過new操作創(chuàng)建的指針,切記在容器對象析構(gòu)前將指針delete掉。切勿創(chuàng)建包含auto_ptr的容器對象。問題的根源只是在于auto_ptr不是這樣的智能指針。
永遠(yuǎn)都不要錯誤的認(rèn)為:你可以通過創(chuàng)建auto_ptr的容器使指針被自動刪除。
慎重選擇刪除元素的方法
erase是指向緊隨被刪除元素的下一個元素的有效迭代器。
要刪除容器中有特定值得所有對象
如果容器使vector、string或deque,則使用earse-remove習(xí)慣用法。
如果容器是list,則使用list::remove
如果容器是一個標(biāo)準(zhǔn)關(guān)聯(lián)容器,則使用它的erase成員函數(shù)。
要刪除容器中滿足特定判別式(條件)的所有對象
如果容器是vector、string或deque,則使用erase-remove_if的習(xí)慣用法。
如果容器是list,則使用list::remove_if。
如果容器使一個標(biāo)準(zhǔn)關(guān)聯(lián)容器,則使用remove_copy_if和swap,或者寫一個循環(huán)來遍歷容器中的元素,記住當(dāng)把迭代器傳給erase時,要對它進(jìn)行后綴遞增。
要在循環(huán)內(nèi)部做某些(除了刪除對象之外的)操作
如果容器使一個標(biāo)準(zhǔn)序列容器,則寫一個循環(huán)來遍歷容器中的元素,記住每次調(diào)用erase時,要用它的返回值更新迭代器。
如果容器是一個標(biāo)準(zhǔn)關(guān)聯(lián)容器,則寫一個循環(huán)來遍歷容器中的元素,記住當(dāng)把迭代器傳給erase時,要對迭代器作后綴遞增。
切勿對STL容器的線程安全性有不切實際的依賴。
你不能指望STL庫會把你從手工同步控制中解脫出來,而且你不能依賴于任何線程的支持。
在容器所返回的每個迭代器的生存期結(jié)束前,都鎖住容器
對于作用于容器的每個算法,都鎖住該容器,直到算法結(jié)束。 多個線程讀是安全的
多個線程對不同的容器作寫入操作時安全的。
對容器成員函數(shù)的每次調(diào)用,都鎖住容器直到調(diào)用結(jié)束。
VIM官網(wǎng):
先是一些vim基本配置設(shè)置
vim語法高亮顯示和自動縮進(jìn)
1、配置文件的位置
在目錄 /etc/ 下面,有個名為vimrc的文件,這是系統(tǒng)中公共的vim配置文件,對所有用戶都有效。而在每個用戶的主目錄下,都可以自己建立私有的配置文件,命名為:“.vimrc”。例如,/root目錄下,通常已經(jīng)存在一個.vimrc文件。
2、設(shè)置語法高亮顯示
1) 打開vimrc,添加以下語句來使得語法高亮顯示:
syntax on
2) 如果此時語法還是沒有高亮顯示,那么在/etc目錄下的profile文件中添加以下語句:
export TERM=xterm-color
3、設(shè)置Windows風(fēng)格的C/C++自動縮進(jìn)(添加以下set語句到vimrc中)
1)設(shè)置(軟)制表符寬度為4:
set tabstop=4
set softtabstop=4
2)設(shè)置縮進(jìn)的空格數(shù)為4
set shiftwidth=4
3)設(shè)置自動縮進(jìn):即每行的縮進(jìn)值與上一行相等;使用 noautoindent 取消設(shè)置:
set autoindent
4)設(shè)置使用 C/C++ 語言的自動縮進(jìn)方式:
set cindent
5)設(shè)置C/C++語言的具體縮進(jìn)方式(以我的windows風(fēng)格為例):
set cinoptions={0,1s,t0,n-2,p2s,(03s,=.5s,>1s,=1s,:1s
6)如果想在左側(cè)顯示文本的行號,可以用以下語句:
set nu
7)最后,如果沒有下列語句,就加上吧:
if &term=="xterm"
set t_Co=8
set t_Sb=^[[4%dm
set t_Sf=^[[3%dm
endif
安裝ctags+taglist 1.ctags
(1)到
http://ctags.sourceforge.net/下載ctags源碼ctags-5.6.tar.gz
http://prdownloads.sourceforge.net/ctags/ctags-5.6.tar.gz(2)解壓并安裝
tar zxvf ctags-5.6.tar.gz
cd ctags-5.6
./configure && make && make install
(3)使用
[/home/brimmer/src]$ ctags -R
"-R"表示遞歸創(chuàng)建,也就包括源代碼根目錄下的所有子目錄下的源程序。"tags"文件中包括這些對象的列表:
l 用#define定義的宏
l 枚舉型變量的值
l 函數(shù)的定義、原型和聲明
l 名字空間(namespace)
l 類型定義(typedefs)
l 變量(包括定義和聲明)
l 類(class)、結(jié)構(gòu)(struct)、枚舉類型(enum)和聯(lián)合(union)
l 類、結(jié)構(gòu)和聯(lián)合中成員變量或函數(shù)
VIM用這個"tags"文件來定位上面這些做了標(biāo)記的對象,下面介紹一下定位這些對象的方法:
1) 用命令行。在運行vim的時候加上"-t"參數(shù),例如:
[/home/brimmer/src]$ vim -t foo_bar
這個命令將打開定義"foo_bar"(變量或函數(shù)或其它)的文件,并把光標(biāo)定位到這一行。
2) 在vim編輯器內(nèi)用":ta"命令,例如:
:ta foo_bar
3) 最方便的方法是把光標(biāo)移到變量名或函數(shù)名上,然后按下"Ctrl-]"。用"Ctrl-o"退回原來的地方。
注意:運行vim的時候,必須在"tags"文件所在的目錄下運行。否則,運行vim的時候還要用":set tags="命令設(shè)定"tags"文件的路徑,這樣vim才能找到"tags"文件。
在函數(shù)中移動光標(biāo)
[{ 轉(zhuǎn)到上一個位于第一列的"{"
}] 轉(zhuǎn)到下一個位于第一列的"{"
{ 轉(zhuǎn)到上一個空行
} 轉(zhuǎn)到下一個空行 ([ and ] 也分別是兩個指令)
gd 轉(zhuǎn)到當(dāng)前光標(biāo)所指的局部變量的定義
* 轉(zhuǎn)到當(dāng)前光標(biāo)所指的單詞下一次出現(xiàn)的地方
# 轉(zhuǎn)到當(dāng)前光標(biāo)所指的單詞上一次出現(xiàn)的地方
Vim 的創(chuàng)造者是一名計算機(jī)程序員,因此這就不奇怪 Vim 中有許多幫助編寫程序的功能:
跳轉(zhuǎn)到標(biāo)識符被定義和使用的地方;在另一個窗口中預(yù)覽有關(guān)的聲明等等。
(ctags使用部分參考了 文章“ctags和vim”,原文在
http://hi.baidu.com/original/blog/item/2cf8d53f00b7fcc27d1e71f0.html,
更多使用也請參考原文)
2. taglist
能夠列出源文件中的tag(function, class, variable, etc)并跳轉(zhuǎn).
注意:taglist依賴于ctags,所以要先裝ctags,否則taglist裝了也沒法用!
(1)到
http://vim.sourceforge.net/scripts/script.php?script_id=273下載taglist_42.zip,即
http://vim.sourceforge.net/scripts/download_script.php?src_id=6416(2)解壓得到兩個文件
# unzip -d taglist taglist_42.zip
# cd taglist
# tree
.
|-- doc
| `-- taglist.txt
`-- plugin
`-- taglist.vim
(3)安裝
cp doc/taglist.txt /usr/share/vim/vim61/doc/
cp plugin/taglist.vim /usr/share/vim/vim61/plugin/
(4)配置和使用
cd /usr/share/vim/vim61/doc/
啟動vim,用 “:helptags .”來配置好幫助文件
重啟vim,用“:TlistToggle”來打開和關(guān)閉taglist窗口。
可以用“:help taglist”來獲得更多幫助信息
set tags=./tags,./../tags,./http://www.cnblogs.com/tags,./**/tags
let Tlist_Use_Left_Window=1
let Tlist_Auto_Update=1
let Tlist_Exit_OnlyWindow=1
let Tlist_Show_One_File=1
nmap <F7> :TlistToggle <CR>
其次安裝配置基本的插件1.安裝好Vim和Vim的基本插件。在ubuntu下這些使用apt-get安裝即可:
lingd@ubuntu:~/arm$sudo apt-get install vim vim-scripts vim-doc
其中vim-scripts是vim的一些基本插件,包括語法高亮的支持、縮進(jìn)等等。
vim中文幫助文檔tar包下載地址:
http://sourceforge.net/projects/vimcdoc/files/vimcdoc/
解壓后其中有個doc文件夾, 將其中的內(nèi)容全部復(fù)制到~/.vim/doc, 或者vim安裝目錄下的doc目錄中, 此時vim中的help信息已經(jīng)是中文的了.
網(wǎng)頁版中文幫助文檔網(wǎng)址http://vimcdoc.sourceforge.net/doc/help.html
首頁就時vim幫助文檔的目錄,閱讀起來更方便有效、更有針對性!
2.管理vim插件——vim-addons
通過vim-addons,我們可以管理vim插件。我們在sudo apt-get install vim vim-scripts vim-doc時,一般會自動安裝上vim-addons。若未安裝可通過sudo apt-get install vim-addon-manager手動安裝。安裝完成后,就可以用vim-addons管理vim插件了。
# 系統(tǒng)中已有的vim-scripts中包含的插件及其狀態(tài):
lingd@ubuntu:~$ vim-addons status
# Name User Status System Status
align removed removed
alternate removed removed
bufexplorer removed removed
calendar removed removed
closetag removed removed
colors sampler pack removed removed
cvsmenu removed removed
debPlugin removed removed
detectindent removed removed
doxygen-toolkit removed removed
editexisting removed removed
enhanced-commentify removed removed
gnupg removed removed
info removed removed
justify removed removed
lbdbq removed removed
markdown-syntax removed removed
matchit removed removed
minibufexplorer installed removed
nerd-commenter removed removed
omnicppcomplete installed removed
po removed removed
project installed removed
python-indent removed removed
secure-modelines removed removed
snippetsEmu removed removed
sokoban removed removed
supertab removed removed
surround removed removed
taglist installed removed
tetris removed removed
utl removed removed
vcscommand removed removed
vimplate removed removed
whatdomain removed removed
winmanager removed removed
xmledit removed removed
Reference:vim配置為C/C++開發(fā)環(huán)境 一步步將vim改造成C/C++開發(fā)環(huán)境(IDE)
-- 引子--
由于調(diào)試需要,需直接往數(shù)據(jù)庫里寫入二進(jìn)制數(shù)據(jù)。本來這些數(shù)據(jù)是由上層軟件來寫的,用的是C#。為了熟悉C語言的數(shù)據(jù)庫操作,還是決定用C來寫這段調(diào)試代碼。
概況:
表名:Task
涉及的字段及屬性:
NumDest:int(11) 用于存儲目標(biāo)數(shù)目
destIDs: blob 用于存儲具體的目標(biāo)ID
廢話不多說,入正題。
--二進(jìn)制數(shù)據(jù)寫入--
二進(jìn)制數(shù)據(jù)最為常見的就是圖片等一些文件信息。雖然我這里不是這類型信息,但確實是二進(jìn)制數(shù)據(jù)。
具體步驟:
1、 定義一個buffer(如數(shù)組)來存儲sql語句
2、 把涉及到二進(jìn)制數(shù)據(jù)之前的sql語句添加到buffer中,可用sprintf或strcpy等。
3、 用mysql_real_escape_string()函數(shù)添加二進(jìn)制數(shù)據(jù)到buffer中。
4、 加上剩余的sql語句,形成完整的sql語句。
5、 利用mysql_real_query()函數(shù)來執(zhí)行sql語句。
具體代碼如下:
#include <stdio.h> #include <stdlib.h> #include <mysql/mysql.h> #include <stdint.h> #include <string.h>
int main(int argc, char *argv[]) { MYSQL mysql; char sql[256], *end; int index, i; uint32_t *destIDs;
if(argc != 2) { printf("enter error!\n"); exit(1); } index = atoi(argv[1]); printf("index: %d\n", index); destIDs = (uint32_t *)malloc(index * sizeof(uint32_t)); if(destIDs == NULL) printf("malloc error\n"); for(i=0; i<index; i++) destIDs[i] = i + 1; mysql_init(&mysql); if(!(mysql_real_connect(&mysql, "localhost", "root", "654321", "dbname", 0, NULL, 0))) { fprintf(stderr, "Couldn't connect to engine!\n%s\n", mysql_error(&mysql)); perror(""); exit(1); }
sprintf(sql, "INSERT INTO Task(NumDest, DestIDs) VALUE (%u, ", index ); end = sql + strlen(sql); *end++ = '\''; end += mysql_real_escape_string(&mysql, end,(char *)destIDs, index*sizeof(uint32_t)); *end++ = '\''; *end++ = ')';
printf("end - sql: %d\n", (unsigned int)(end - sql));
if(mysql_real_query(&mysql, sql, (unsigned int)(end - sql))) { fprintf(stderr, "Query failed (%s)\n", mysql_error(&mysql)); exit(1); } mysql_close(&mysql); exit(0); #endif return 0; }
|
--讀取二進(jìn)制文件--
對于二進(jìn)制文件的讀取,也類似。
具體步驟:
1,構(gòu)造查詢字串.
2,執(zhí)行mysql _query查詢. (網(wǎng)上有說用mysql_real_query,未實驗)
3,用mysql_store_result存儲結(jié)果.
4,用mysql_fetch_row取出一條記錄處理.
具體代碼如下:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <mysql/mysql.h> #include <string.h>
int main(void) { int ret, i; char sql[256]; MYSQL mysql; MYSQL_RES *result; MYSQL_ROW row; uint32_t *destIDs, *temp; unsigned int destNum = 0;
mysql_init(&mysql); if(!(mysql_real_connect(&mysql, "localhost", "root", "654321", "dbname", 0, NULL, 0))) { fprintf(stderr, "Couldn't connect to engine!\n%s\n", mysql_error(&mysql)); perror(""); exit(1); }
sprintf(sql, "SELECT TaskID, NumDest, DestIDs FROM Task"); ret = mysql_query(&mysql, sql); if(ret != 0) { printf( "Failed to query task table: %s\n", mysql_error(&mysql)); return ret; }
result = mysql_store_result(&mysql); if(result == NULL) { ret = mysql_errno(&mysql); printf( "Failed to store query result from task table:%s\n", mysql_error(&mysql)); return ret; }
if((row = mysql_fetch_row(result)) != NULL) { sscanf(row[1], "%u", &destNum);
destIDs = (uint32_t *)malloc(destNum * sizeof(uint32_t)); if(destIDs == NULL) { printf("malloc error!\n"); exit(1); } memcpy(destIDs, row[2], destNum * sizeof(uint32_t)); }
mysql_free_result(result);
printf("destNum: %d\n", destNum); temp = destIDs; for(i=0; i<destNum; i++) { printf("destIDs[%d]:%d\t", i+1, *temp++); }
return ret; }
|
由于我這里可以根據(jù)NumDest獲取到二進(jìn)制的長度,所以不用再用函數(shù)去獲取。
據(jù)網(wǎng)上信息,獲取二進(jìn)制信息長度應(yīng)該這樣:“如果取出來的是二進(jìn)制的數(shù)據(jù),要確定它的長度,必須要用mysql_fetch_lengths函數(shù)取得其長度”
int num_fields = mysql_num_fields(result); unsigned long *lengths = mysql_fetch_lengths(result); for(i=0; i<num_fields; i++) printf("Column: %u\t %lu bytes\n", i+1, lengths[i]); destIDs = (uint32_t *)malloc(lengths[2]); if(destIDs == NULL) { printf("malloc error!\n"); exit(1); } memcpy(destIDs, row[2], lengths[2]);
|
取二進(jìn)制數(shù)據(jù):
一樣的sql語句,查詢出來即可。只不過二進(jìn)制數(shù)據(jù)是個數(shù)據(jù)塊,需要得到數(shù)據(jù)塊的大小和數(shù)據(jù)指針。
bool CMySqlAccess::GetBinaryField(int nCol,char* &pDataOut,int& nDataLen)
{
if (m_ItemMySqlRow[nCol] != NULL)
{
unsigned long *FieldLength = mysql_fetch_lengths(m_pMySqlResult);
nDataLen = (int)FieldLength[nCol];
pDataOut = (char*)(m_ItemMySqlRow[nCol]);
return true;
}
else
{
return false;
}
}
像通常一樣查詢后,得到結(jié)果集,然后得到第nCol列結(jié)果,返回二進(jìn)制指針結(jié)果和二進(jìn)制長度。返回后必須立馬處理或者存儲一份。否則mysql將數(shù)據(jù)銷毀,指針?biāo)笖?shù)據(jù)則無效了。
存二進(jìn)制數(shù)據(jù):
mysql語句接受的sql語句都是string,以'\0'結(jié)尾的。如果冒然插入二進(jìn)制數(shù)據(jù)到sql語句中,要么報錯,要么存儲錯誤。此處可以通過mysql提供的函數(shù)將數(shù)據(jù)轉(zhuǎn)換一下即可。
char* CMySqlAccess::ConvertBinaryToString(char* pBinaryData,int nLen)
{
static char s_BinaryData[10240];
mysql_real_escape_string(m_pMySqlConn,s_BinaryData,pBinaryData,nLen);
return s_BinaryData;
}
上面這個函數(shù)只能單線程使用啊,將一塊二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為mysql可識別的string數(shù)據(jù)。這樣就直接可以通過mysql的sql語句insert,update來對blob數(shù)據(jù)進(jìn)行更新和插入了,sql語句用法不變。
用例:
std::ostringstream strSQL;
strSQL<<"INSERT INTO "<<m_strTableName<<"(roleid,playerdata,dynamicdata) VALUES("<<dwDBRoleID
<<",'"<<m_pDBAccess->ConvertBinaryToString(pData,nLen)<<"','')";
assert(m_pDBAccess);
m_pDBAccess->ExecuteSQL(strSQL.str());
playerdata是blob二進(jìn)制類型,pData是指向一個結(jié)構(gòu)體的指針,nLen是結(jié)構(gòu)體的大小。
上面就可以實現(xiàn)二進(jìn)制的存儲了。
方法二:
上面的方法,你會發(fā)現(xiàn),你每次都需要轉(zhuǎn)換數(shù)據(jù),傳指針,傳大小等一系列復(fù)雜操作,是不是順序很混亂,過程很繁雜。mysql也為你提供了另外一種方法,那就是MYSQL_BIND。將數(shù)據(jù)操作統(tǒng)一化,統(tǒng)一麻煩化。mysqlbind是一個結(jié)構(gòu)體,根據(jù)個人不同需求填充各個數(shù)據(jù)成員可以存儲任意類型數(shù)據(jù),當(dāng)然包括blob。
bool CMySqlAccess::SetBinaryField(std::string& strCondition,void* pDataIn,int nDataLen)
{
if( ! mysql_stmt_prepare( m_pMySqlStmt, strCondition.c_str(), strCondition.length() ) )
{
memset(&m_MySqlBind,0,sizeof(MYSQL_BIND));
m_MySqlBind.buffer_type = MYSQL_TYPE_BLOB;
(*m_MySqlBind.length) = nDataLen;
memcpy(m_MySqlBind.buffer,pDataIn,nDataLen);
if(!mysql_stmt_bind_param(m_pMySqlStmt, (MYSQL_BIND *)&m_MySqlBind))
{
if(!mysql_stmt_execute(m_pMySqlStmt))
{
return true;
}
}
}
int nRes=GetDBErrorCode();
CLogOutStream errLog(crazy::ERROR_LEVEL,THIS_CLASS_NAME);
errLog<<"MySql Query Failed:\""<<strCondition<<"\" ,ErrorCode:"<<nRes<<crazy::logEnd;
return false;
}
這個是對某一列blob數(shù)據(jù)進(jìn)行存操作。pDataIn和nDataLen分別是一個struct結(jié)構(gòu)體和結(jié)構(gòu)體大小。填充完畢mysqlbind之后即可對數(shù)據(jù)庫二進(jìn)制列進(jìn)行存儲了。可能你會問,沒有指定哪一列呢,對。哪一列是在strCondition語句里面的,這是一個預(yù)處理語句。在預(yù)處理語句里面,有一個符號: ? 。問號,問號的位置代表了mysqlbind數(shù)據(jù)對應(yīng)的位置。
INSERT INTO test_table(date_field, time_field, timestamp_field) VALUES(?,?,?)
上面這個語句,有3個問號,三個問號分別對應(yīng)test_table的三列.每個問號呢又對應(yīng)一個mysqlbind數(shù)據(jù)結(jié)構(gòu)。那么我們在mysql_stmt_bind_param函數(shù)調(diào)用時,就應(yīng)該傳入一個mysql_bind 數(shù)組。MYSQL_BIND m_MySqlBind[3].
填充整個數(shù)組數(shù)據(jù),即對應(yīng)三個問號內(nèi)容。
用例:
MYSQL_BIND bind[3];
MYSQL_STMT *stmt;
strmov(query, "INSERT INTO test_table(date_field, time_field, timestamp_field) VALUES(?,?,?");
//初始化stmt
stmt = mysql_stmt_init(mysql);
//預(yù)處理語句
mysql_stmt_prepare(mysql, query, strlen(query));
//初始化參數(shù)
bind[0].buffer_type= MYSQL_TYPE_DATE;
bind[0].buffer= (char *)&ts;
bind[0].is_null= 0;
bind[0].length= 0;
bind[1]= bind[2]= bind[0];
//綁定參數(shù)123
mysql_stmt_bind_param(stmt, bind);
//執(zhí)行預(yù)處理mysql語句
mysql_stmt_execute(stmt);
還沒看懂就個人去看mysql文檔了,其實里面講得很清楚,只要找對幾個函數(shù),就可以把search出來了
轉(zhuǎn)自:http://blog.chinaunix.net/uid-23842323-id-2656614.html
Reference:http://topic.csdn.net/u/20090316/11/ac003f13-d1da-49a5-b12f-90e57cbe5ac9.html
摘要: 這些小技巧之所以特別,是因為這些信息通常吧不能在C++書籍或者網(wǎng)站上找到。比如說,成員指針,即使對于高級程序員也是比較棘手,和易于產(chǎn)生bugs的,是應(yīng)該盡量避免的問題之一。
<翻 by凌云健筆>
What makes these tips special is that the information they provide usually cannot be found in ...
閱讀全文
Good cooking takes time. If you are made to wait, it is to serve you better, and to please you.
美食的烹飪需要時間;片刻等待,更多美味,更多享受。
Adding manpower to a late software project makes it later.
向進(jìn)度落后的項目中增加人手,實惠使進(jìn)度更加落后。
對結(jié)構(gòu)師的建議:
- 牢記是開發(fā)人員承擔(dān)創(chuàng)造性和發(fā)明性的實現(xiàn)責(zé)任,所以結(jié)構(gòu)師只能建議,而不能支配
- 時刻準(zhǔn)備著為所指定的說明建議一種實現(xiàn)的方法,同樣準(zhǔn)備接受其他任何能達(dá)到目標(biāo)的方法
- 對上述的建議保持低調(diào)和不公開
- 準(zhǔn)備放棄堅持所做的改進(jìn)建議
一般開發(fā)人員會反對體系結(jié)構(gòu)上的修改建議。通常他是對的——當(dāng)正在實現(xiàn)產(chǎn)品時,某些次要特性的修改會造成意料不到的成本開銷。
Practice is the best of all instructors.
實踐是最好的老師。
Experence is a dear teacher, but fools will learn at no other.
實踐是最好的老師,但智者還能從其他地方有所收獲。
There is nothing in this world constant but inconstancy.
不變只是愿望,變化才是永恒。
It is commeon sense to take a method and try it. If it fails, admit it frankly and try another. But above all, try something.
普遍的做法是,選擇一種方法,試試看;如果失敗了,沒關(guān)系,再試試別的。不管怎么樣,重要的是先去嘗試。
What we do not understand we do not possess.
不了解,就無法真正擁有。
For brevity is very good, Where we are , or are not understood.
我們理解也好,不理解也好,描述都應(yīng)該簡短精煉。
記錄DirectX和OpenGL渲染的動畫簡介 當(dāng)我們創(chuàng)建游戲和仿真模擬時,有時我們有必要記錄渲染的內(nèi)容。在某些情況下渲染過于復(fù)雜和耗時,這是不可避免的。
在DirectX中,庫函數(shù)D3DXSaveSurfaceToFile()保存表面為一張圖片文件。對OpenGL,我們用glReadPixels()來讀渲染的圖像像素然后手動的保存它們?yōu)橐粡垐D片文件。然而這些表面只是針對單幀記錄的,對記錄一段連續(xù)幀沒有簡單的方法存在。換句話說,沒有庫函數(shù)來記錄我們的完整存在渲染動畫效果。
在這方面,本文提出了幾類,這有助于創(chuàng)造電影DirectX的方法和動畫。用類CDxToMovie和 CGLToMovie電影可以選擇性地或連續(xù)的從DirectX和OpenGL渲染幀來創(chuàng)建。一般來說,一個典型的電影創(chuàng)作過程涉及復(fù)雜的任務(wù),例如讀圖的內(nèi)容,選擇幀速率設(shè)置,編解碼器的設(shè)置,初始化媒體流,寫媒體流等(詳細(xì)討論關(guān)于如何創(chuàng)建位圖圖像序列的電影,請參考這篇文章
Create Movie from HBitmap)。類CDxToMovie和CGLToMovie這里介紹的抽象出所有不必要的復(fù)雜性和易于使用的界面,提供簡單方法解釋如下
從DirectX渲染序列記錄一個電影
類CDxToMovie可以記錄DirectX渲染序列成電影文件。該類用到DirectX 9.0接口例如LPDIRECT3DSURFACE9,因此你應(yīng)該用DirectX 9.0 SDK 或者其他的兼容的地方使用這個類 。
開始從本文中的DirectX代碼拷貝文件DxToMovie.h,RenderTarget.h,AviFile.h和AviFile.cpp到你的工程目錄下然后添加他們到你的工程中,然后添加vfw.lib,一旦添加到你的工程中,你可以通過#include "DxToMovie.h"訪問。CDxToMovie構(gòu)造函數(shù)接受不同的參數(shù)如輸出電影文件名,電影幀的寬度和高度的要求,每像素比特數(shù)等…如下所示,
CDxToMovie(LPCTSTR lpszOutputMovieFileName = _T("Output.avi"),

int nFrameWidth = GetSystemMetrics(SM_CXSCREEN), /**//*Movie Frame Width*/

int nFrameHeight = GetSystemMetrics(SM_CYSCREEN), /**//*Movie Frame Height*/

int nBitsPerPixel = 32, /**//*Bits per Pixel*/

DWORD dwCodec = mmioFOURCC('M','P','G','4'), /**//*Video Codec for Compression*/

DWORD dwFrameRate = 1) /**//*Frame Rate (FPS) setting for the Movie*/

然而,應(yīng)該注意到的是,這是一個時間設(shè)置,后來在電影記錄時候不能改變 。每個CDxToMovie對應(yīng)一個不同的電影文件和再造一個CDxToMovie對象具有相同的輸出文件的名字不會追加以前的電影內(nèi)容,將覆蓋它。
CDxToMovie g_MovieRecorder("Output.Avi", 320, 240); 一旦創(chuàng)建CDxToMovie對象,方法CDxToMovie::OnCreateDevice()在你的程序Direct3D設(shè)備創(chuàng)建的時候會被調(diào)用。類似的,CDxToMovie::OnLostDevice(),CDxToMovie::OnResetDevice()和CDxToMovie::OnDestroyDevice()也會在設(shè)備丟失銷毀的時候各自被調(diào)用。這些函數(shù)的原型顯示如下
class CDxToMovie

{
HRESULT OnCreateDevice(LPDIRECT3DDEVICE9 pd3dDevice);
HRESULT OnDestroyDevice(LPDIRECT3DDEVICE9 pd3dDevice);
HRESULT OnLostDevice();
HRESULT OnResetDevice(LPDIRECT3DDEVICE9 pd3dDevice,
const D3DSURFACE_DESC* pBackBufferSurfaceDesc);
};函數(shù)OnCreateDevice()和OnDestroyDevice()接受一個單單參數(shù),指向你程序的Direct3D設(shè)備對象。OnLostDevice()沒有參數(shù),但是OnResetDevice()還要有一個指針指向你設(shè)備的后緩沖區(qū)表面 D3DSURFACE_DESC*。CDxToMovie對象提供一些信息在D3DSURFACE_DESC里 創(chuàng)造一個合適的offscreen渲染目標(biāo),可以用來記錄你的應(yīng)用程序的渲染。
真正記錄的功能是通過函數(shù)CDxToMovie::StartRecordingMovie()和CDxToMovie::PauseRecordingMovie().這兩個函數(shù)必須每一幀都要在
IDirect3DDevice9::BeginScene() 和
IDirect3DDevice9::EndScene()之間。如下所示
g_pd3dDevice->BeginScene();

// Capture the Rendering onto CDxToMovie's Render Target
g_MovieRecorder.StartRecordingMovie(g_pd3dDevice);
// Render as usual
..
g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,200),1,0);
g_pd3dDevice->SetStreamSource(0,g_pVB,0,sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);
g_MovieRecorder.PauseRecordingMovie(g_pd3dDevice);

// Copy the CDxToMovie's Render Target content back onto BackBuffer's Surface
g_pd3dDevice->StretchRect(g_MovieRecorder.RecordingSurface(),
NULL,pBackSurface,
0,D3DTEXF_NONE);

g_pd3dDevice->EndScene();
在上面的代碼段中,
g_MovieRecorder.StartRecordingMovie(g_pd3dDevice)
將所有隨后的渲染在CDxToMovie的內(nèi)部渲染目標(biāo)直到
g_MovieRecorder.PauseRecordingMovie(g_pd3dDevice)被調(diào)用。所有的渲染工作在CDxToMovie的內(nèi)部渲染目標(biāo)上做,你的程序back surface將沒有任何有效的內(nèi)容顯示在你的應(yīng)用程序窗口。這不要緊,如果你的申請不只是創(chuàng)作這部電影沒有任何動畫直接呈現(xiàn)在屏幕上。然而,如果你記錄電影從一個互動游戲會話上,它會變壞屏幕不更新到最新的渲染的內(nèi)容(因為通過重新渲染目標(biāo),CDxToMovie內(nèi)容被偷了)。為了避免它,你可以選擇性地復(fù)制回CDxToMovie內(nèi)部的渲染目標(biāo)的內(nèi)容到你的應(yīng)用程序的back surface 使用方法IDirect3DDevice9:StretchRect(),其次是常見的g_pd3dDevice - > EndScene()和g_pd3dDevice - >Present()的要求會更新內(nèi)容的呈現(xiàn)在屏幕上背緩沖區(qū),使屏幕上更新。
如果你想避免一些幀被選擇性記錄在這部電影,只是不要叫g(shù)_MovieRecorder.StartRecordingMovie和g_MovieRecorder.PauseRecordingMovie()(相應(yīng)的 g_pd3dDevice - > StretchRect())對那些幀,并會直接渲染動畫在屏幕上(沒有被重定向到CDxToMovie內(nèi)部的渲染目標(biāo))。
演示代碼提供這個項目提供了一個簡單的應(yīng)用程序,使得DirectX屏幕上的一個三角形的動作,鼠標(biāo)移動窗戶上,這將simulatenously被渲染成電影文件和記錄(名叫output.avi)。跑演示的可執(zhí)行程序,確保你有MPG4編解碼器的計算機(jī)上安裝,目錄有寫權(quán)限去創(chuàng)建輸出電影文件。詳情請設(shè)置解碼器和平衡,請參考這篇文章
Create Movie from HBitmapRecording a Movie from OpenGL Rendered Sequence先暫時不翻譯了,以后再翻。
注:第一次翻譯,水平比較差,還望各位看客見諒。
Reference:
Recording DirectX and OpenGL Rendered Animations
gcc編譯的幾種錯誤信息及其解決方法
1.語法錯誤
一般實在輸入代碼時括號不匹配或者使用了關(guān)鍵字。遇到語法錯誤,可以仙劍次錯誤提示中出現(xiàn)的第一個行號,如果該行沒有問題,就檢查該行所開始的語法模塊是否完整,然后修正該結(jié)構(gòu)。
2.頭文件錯誤
如果編譯器出的錯誤提示說can not find include file ***.h,就說明是指定的包含文件有問題,系統(tǒng)在編譯過程中找不到指定的頭文件
3.類庫錯誤
如果出現(xiàn)類似“ld:-lm:No such file or directory”的錯誤,可能是在默認(rèn)的目錄內(nèi)找不到相應(yīng)的類庫。這種問題的解決方法是在編譯時使用-I參數(shù)指定要使用的類庫所在的目錄。
4.未定義符號
出現(xiàn)類似Undefined symbol 的提示,說明在編譯過程中發(fā)現(xiàn)了沒有被定義的符號變量
gdb簡介
gdb 程序名
gdb
這兩種方式均可進(jìn)入gdb的交互式調(diào)試界面。在交互模式中可以使用許多命令:
- file;加載要調(diào)試的程序
- kill;終止正在調(diào)試的程序
- list;列出10行程序的源代碼
- next;單步執(zhí)行程序
- step;單步執(zhí)行程序,與next不同的是,其會進(jìn)入調(diào)用的函數(shù)內(nèi)部。而next只需要調(diào)用函數(shù)的結(jié)果。
- run;運行加載的程序
- quit;退出gdb
- watch;監(jiān)視一個變量的值
- break;在代碼里設(shè)置斷點,程序運行到斷點處時會停下來,然后用戶可用next或step單步執(zhí)行程序。但使用break的前提是程序在編譯時使用了g參數(shù)
- make;不用退出gdb,重新編譯代碼,然后在gdb中運行
- shell;可調(diào)用shell命令
- bt;查看函數(shù)堆棧
- c函數(shù);繼續(xù)運行
- finish;退出函數(shù)
- info;查看相關(guān)信息,如info break
假設(shè)我們有下面這樣的一個程序,源代碼如下:

/**//* main.c */
#include "mytool1.h"
#include "mytool2.h"
int main(int argc,char **argv)


{
mytool1_print("hello");
mytool2_print("hello");
}

/**//* mytool1.h */
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char *print_str);
#endif

/**//* mytool1.c */
#include "mytool1.h"
void mytool1_print(char *print_str)


{
printf("This is mytool1 print %s\n",print_str);
}

/**//* mytool2.h */
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
#endif

/**//* mytool2.c */
#include "mytool2.h"
void mytool2_print(char *print_str)


{
printf("This is mytool2 print %s\n",print_str);
}

當(dāng)然由于這個程序是很短的我們可以這樣來編譯
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
這樣的話我們也可以產(chǎn)生main 程序,而且也不時很麻煩.但是如果我們考慮一下如果有一天我們修改了其中的一個文件(比如說mytool1.c)那么我們難道還要重新輸入上面的命令?也許你會說,這個很容易解決啊,我寫一個SHELL 腳本,讓她幫我去完成不就可以了.是的對于這個程序來說,是可以起到作用的,但是當(dāng)我們把事情想的更復(fù)雜一點,如果我們的程序有幾百個源程序的時候,難道也要編譯器重新一個一個的去編譯?
為此,聰明的程序員們想出了一個很好的工具來做這件事情,這就是make.我們只要執(zhí)行以下make,就可以把上面的問題解決掉.在我們執(zhí)行make 之前,我們要先編寫一個非常重要的文件.--Makefile.對于上面的那個程序來說,可能的一個Makefile 的文件是:
# 這是上面那個程序的Makefile 文件
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
有了這個Makefile 文件,不過我們什么時候修改了源程序當(dāng)中的什么文件,我們只要執(zhí)行make 命令,我們的編譯器都只會去編譯和我們修改的文件有關(guān)的文件,其它的文件她連理
都不想去理的。
下面我們學(xué)習(xí)Makefile 是如何編寫的。
在Makefile 中也#開始的行都是注釋行.Makefile 中最重要的是描述文件的依賴關(guān)系的說明.一般的格式是:
target: components
TAB rule
第一行表示的是依賴關(guān)系.第二行是規(guī)則.
比如說我們上面的那個Makefile 文件的第二行
main:main.o mytool1.o mytool2.o
表示我們的目標(biāo)(target)main 的依賴對象(components)是main.o mytool1.o mytool2.o
當(dāng)倚賴的對象在目標(biāo)修改后修改的話,就要去執(zhí)行規(guī)則一行所指定的命令.就象我們的上面那個Makefile 第三行所說的一樣要執(zhí)行 gcc -o main main.o mytool1.o mytool2.o
注意規(guī)則一行中的TAB 表示那里是一個TAB 鍵Makefile 有三個非常有用的變量.分別是
$@,$^,$<代表的意義分別是:
$@--目標(biāo)文件,$^--所有的依賴文件,$<--第一個依賴文件.
如果我們使用上面三個變量,那么我們可以簡化我們的Makefile 文件為:
# 這是簡化后的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
main.o:main.c mytool1.h mytool2.h
gcc -c $<
mytool1.o:mytool1.c mytool1.h
gcc -c $<
mytool2.o:mytool2.c mytool2.h
gcc -c $<
經(jīng)過簡化后我們的Makefile 是簡單了一點,不過人們有時候還想簡單一點.這里我們學(xué)習(xí)一個Makefile 的缺省規(guī)則
..c.o:
gcc -c $<
這個規(guī)則表示所有的 .o 文件都是依賴與相應(yīng)的.c 文件的.例如mytool.o 依賴于mytool.c
這樣Makefile 還可以變?yōu)椋?br /># 這是再一次簡化后的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
..c.o:
gcc -c $<
Makefile的處理規(guī)則
make命令在處理makefile時是遞歸處理的。同時,make在處理makefile時會檢測目標(biāo)文件與依賴文件的時間戳。這個特性降低了編譯文件時的時間開銷,因為其只增量編譯更新過的文件。還有一點要注意的是,makefile文件必須以makefile或Makefile為名。
對簡單Makefile文件的擴(kuò)充
Makefile文件就像是一種小型的腳本語言,所以其也支持變量的定義,而靈活使用變量,可以增強Makefile的適應(yīng)性與靈活性。下面是一個使用變量的Makefile。
##########################################
NAME = myfirst
cc = gcc
ac = as
CFLAG = -Wall -o1 -g
#這是編譯源程序的編譯選項,具體含義可參見前面gcc參數(shù)介紹
${NAME} asfile : ${NAME}.o asfile.o
#使用變量時,應(yīng)該使用$提取符,然后用大括號將變量名括起來
${cc} ${CFLAG} ${NAME}.o -o ${NAME}
${cc} ${CFLAG} asfile.o -o asfile
${NAME}.o : ${NAME}.c
${cc} -c ${NAME}.c -o ${NAME}.o
asfile.o : ${NAME}.s
${ac} ${NAME}.s -o asfile.o
#由匯編代碼生成目標(biāo)文件
${NAME}.s : ${NAME}.c
${cc} -S ${NAME}.c -o ${NAME}.s
#生成匯編代碼的方法
other : ${NAME}.o
#other選項并未出現(xiàn)在最終目標(biāo)中,所以直接使用make命令不會執(zhí)行這一行。要執(zhí)行這一行,必須使用make other來執(zhí)行
${cc} ${CFLAG} ${NAME}.o -o other
#這里并未使用顯示規(guī)則來指定${NAME}.o的生成方式,因為對于make命令而言,如果在規(guī)則中發(fā)現(xiàn)name.o文件,其會自動尋找同名的c代碼(name.c),然后自動根據(jù)找到的代碼調(diào)用相應(yīng)的編譯器編譯生成name.o文件
好了,我們的Makefile 也差不多了,如果想知道更多的關(guān)于Makefile 規(guī)則可以查看相應(yīng)的文檔。