寫程式是一種態度(二)四倍速memmove (轉)
最近在網上發現一個有趣的現象,一些公司的技術面試總是光顧一些常用的ANSI C,我去年也有幸碰到了實現一個簡單scanf的命題。這類題,表面上看實際上都不難,但是想把它考慮全面,寫的精煉且高效卻很難,沒有一定內功的人是達不到這個水準的,這也是頻頻被用來做測試人才尺子的原因。
:namespace prefix = o ns = "urn:schemas--com::office" />
其實很早就知道有些高手為了練內功在讀C run-time程式碼,於是也深入了一段時間,同時我將視野放的更廣一些,涉及到了更多的經典程式碼,對端正我的寫態度起了很大的作用。趁這段時間辟穀,希望用這個系列把一些點滴記錄下來,藉著同廣大網友交流的絕好時機,再重新審視一番我的思路。
先要感謝第一位給我的“寫程式是一種態度(一)strcmp”回覆的網友darkay,將我的視線移入了更有興趣的話題。我提到MS run-time用C來實現函式如strcmp只是演算法的表徵,相對應的都有asm如strcmp.asm才是對其演算法的具體的針對指令集的高效實現。如此可以做一個也許不恰當的類比,strcmp.c是一個偽碼描述,而strcmp.asm才是具體實現;因為用某種c編譯後的strcmp.c很可能沒有直接的strcmp.asm更高效,儘管演算法的思路沒有變化。藉著這個話題我們在看一看經典的memcpy和memmove:
void * __cdecl memcpy (
void * dst,
const void * src,
size_t count
)
{
void * ret = dst;
/*
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
return(ret);
}
void * __cdecl memmove (
void * dst,
const void * src,
size_t count
)
{
void * ret = dst;
if (dst <= src || (char *)dst >= ((char *)src + count)) {
/*
* Non-Overlap Buffers
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}
else {
/*
* Overlapping Buffers
* copy from higher addresses to lower addresses
*/
dst = (char *)dst + count - 1;
src = (char *)src + count - 1;
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst - 1;
src = (char *)src - 1;
}
}
return(ret);
}
這裡我省掉了
#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) || defined (_M_IA64)
編譯開關裡的CODE,針對這些目標機有另外的處理,我們現在只定位於Intel 32-bit上。
1.文件中說的很清楚memcpy不考慮重疊,而memmove會考慮,實際上程式碼中很明顯,memcpy只是memmove的一個子集,所以建議總是用memmove這樣可以不考慮記憶體重疊問題。
2.考慮能否用C++去描述更精煉?如從低地址到高地址的賦值可以簡單寫成:
while (count--) {
*dst ++ = *src ++;
}
3.c編譯器對以上程式碼編譯後所產生的指令是否是一個位元組一個位元組複製?
4.問題3將帶來我們對副標題的討論--四倍速
Intel 80386以上支援的指令集中MOVSD指令和REP指令配合將D(32bit)在記憶體間移動,即在一個時鐘週期copy四個位元組,整整比MOVSB(8bit)指令快了四倍。但是使用MOVSD移動到的目的記憶體地址必須是32bit對齊的(DWORD-aligned)。簡單說明從低位到高位的記憶體copy如下。
設L為要複製的總位元組數,Dest為目的起始地址,X為從Dest開始沒有DWORD-aligned的位元組數,Y為要複製的DWORD個數,Z為剩餘的沒有DWORD-aligned位元組數。那麼有公式如下:
X = (4 – Dest & 3 ) & 3 (bytes) //低兩位為0的地址是DWORD-aligned
Y = (L – X) >> 2 (DWORDs) //整除以4是DWORD個數
Z = (L – X – Y * 4) (bytes)
再做相應的處理。
總結一下,對大段的記憶體移動,用memmove將是非常的,相反若用c寫的code會降低四倍,這就是為什麼要用ASM直接實現的原因。其實讀程式也是一種態度,不知道我是否鑽了牛角尖了,但願不是。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992700/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 寫程式是一種態度(一)strcmp (轉)
- 換一種態度看程式設計師!程式設計師
- 40 歲了還在寫程式碼,是一種幸福,還是一種悲哀?
- 如果40歲了還在寫程式碼,是一種幸福,還是一種悲哀?
- 如果40歲了還在寫程式碼 是一種幸福 還是一種悲哀?
- Serverless 是一種思想狀態Server
- 寫網路爬蟲程式的三種難度爬蟲
- [資料結構] 二分查詢 (四種寫法)資料結構
- 動態加栽程式集(二) (轉)
- 處理物件的多種狀態及其相互轉換——狀態模式(四)物件模式
- 程式設計師的nginx技能包(4)——埠轉發,節約是一種美德,規範是一種程式設計師Nginx
- “全棧開發者”是一種心態 - Maciej Walkowiak全棧Mac
- 在大公司寫程式碼是一種什麼樣的體驗?
- 編寫可維護的程式碼是一種溝通技巧 - Max Chernyak
- Linux網路驅動程式編寫(四)(轉)Linux
- 快速掌握RabbitMQ(二)——四種Exchange介紹及程式碼演示MQ
- 假如女人是一種程式語言
- 空杯求學 - 學習是一種心態
- 四種Blog程式
- 四種IT治理方法(轉載)
- 程式設計:Java抽取Word,PDF的四種武器(轉)程式設計Java
- 二叉樹四種遍歷二叉樹
- TDengine 支援多種寫入協議,四種寫入方式提效大全協議
- [譯]mock 是一種程式碼異味(軟體編寫)(第十二部分)Mock
- Linux網路驅動程式編寫(二)(轉)Linux
- 生活一種狀態,關鍵是要給自己定位
- memcpy,memmove的實現memcpy
- 霍炬:程式設計師愛寫指令碼是種病程式設計師指令碼
- synchronized四種鎖狀態的升級synchronized
- css中按鈕的四種狀態CSS
- 程式設計師的三階段,薪資的三大“關”,你對程式設計到底持有的是一種什麼樣的態度?程式設計師
- 回字有四種寫法,那你知道單例有五種寫法嗎單例
- hibernate(二)一級快取和三種狀態解析快取
- 理解 TCP(四):狀態流轉TCP
- C語言-記憶體函式的實現(二)之memmoveC語言記憶體函式
- 編寫一個程式求輸入字串的長度字串
- 二分查詢 | 二分查詢的一種推薦寫法
- 支付寶王益:40歲寫30年程式碼是一種什麼體驗?