日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dietlibc中的strcpy算法浅析

發布時間:2024/9/5 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dietlibc中的strcpy算法浅析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://sunxiunan.com/?p=1640

我們將代碼稍作修改,讓一些宏定義變成函數更容易理解一些:

#include "stdafx.h" #include <stdio.h> /* fast strcpy -- Copyright (C) 2003 Thomas M. Ogrisegg <tom@hi-tek.fnord.at> */ //#include <string.h> //#include "dietfeatures.h" //#include "dietstring.h" // ----following are dietstring.h content. //#include <endian.h> //# define MKW(x) (x|x<<8|x<<16|x<<24) int MKW(int x) { x = x | x<<8 | x << 16 | x << 24; return x; }//# define STRALIGN(x) (((unsigned long)x&3)?4-((unsigned long)x&3):0) unsigned long STRALIGN(unsigned long xPtr) { unsigned long xRet = (unsigned long)xPtr & 3; if (xRet) xRet = 4 - ((unsigned long) xPtr & 3); else xRet = 0; return xRet; }/* GFC(x) - returns first character */ /* INCSTR(x) - moves to next character */ # define GFC(x) ((x)&0xff) # define INCSTR(x) do { x >>= 8; } while (0)//#define UNALIGNED(x,y) (((unsigned long)x & (sizeof (unsigned long)-1)) ^ ((unsigned long)y & (sizeof (unsigned long)-1))) unsigned long MyUnaligned(unsigned long xPtr, unsigned long yPtr) { unsigned long valN1 = sizeof (unsigned long)-1; unsigned long xVal = (unsigned long) xPtr & valN1; unsigned long yVal = (unsigned long) yPtr & valN1; unsigned long retVal = xVal ^ yVal; return retVal; } // ----above are dietstring.h content.char * strcpy2 (char *s1, const char *s2) {char *res = s1;int tmp;unsigned long l;if (MyUnaligned((unsigned long)s1, (unsigned long)s2)){ while ((*s1++ = *s2++)); return (res);}if ((tmp = STRALIGN((unsigned long)s1))){ while (tmp-- && (*s1++ = *s2++)); if (tmp != -1) return (res);}while (1) { unsigned long key1 = MKW(0x1ul); unsigned long key2 = MKW(0x80ul);l = *(const unsigned long *) s2;if (((l - key1) & ~l) & key2) { while ((*s1++ = GFC(l))) INCSTR(l); return (res); }*(unsigned long *) s1 = l; s2 += sizeof(unsigned long); s1 += sizeof(unsigned long); } }int _tmain(int argc, _TCHAR* argv[]) { char* p = (char*)malloc(50* sizeof p); char* str = "aaaabbbbbcccccc"; strcpy2(p, str); free(p); return 0; }

為了不和標準庫的strcpy名字沖突,我將其改為strcpy2.

如果你把上面的程序編譯運行一下就會發現,快的原因在于strcpy2這個函數最后一部分while循環里面的這幾行:

*(unsigned long *) s1 = l;

?

s2 += sizeof(unsigned long);

s1 += sizeof(unsigned long);

對C語言指針了解的朋友都知道,第一行是把l這個unsigned long類型變量值賦值給s1為地址的一個unsigned long型指針指向的內容。

在我的i386cpu PC機上,第二第三行分別是將s2以及s1指針增加了4(而不是通常函數實現里面的++)。這也就實現了每次拷貝4個char(也就是一個unsigned long)而不是只拷貝一個char。

而strcpy2前面的函數就是確保這個拷貝可以正確執行。

我們先看MyUnaligned這個函數(在dietlibc中原為UNALIGNED宏)。

先取了一個值是sizeof(unsigned long) – 1,然后將源字符串指針以及目標字符串指針都與這個值做與操作(xPtr & valN1),最后兩個結果做一個異或xor操作(xVal ^ yVal)。

其實說白了很簡單,xPtr & valN1相當于一個取模操作,i386 cpu上valN1的值為3,也就是與的結果可能為0,1,2,3,當xPtr或者yPtr的值為4的倍數時候,與操作得到結果為0。兩個與操作結果做一下異或,只有都為0或者都為1的時候,返回為0。也就是只要有一個指針沒對齊,就老老實實的做一個個char的拷貝(*s1++ = *s2++),然后從strcpy2返回。

這個算法就是為了保證xPtr以及yPtr指針都是在內存上是對齊的(aligned),如果沒有對齊還要一次賦值4個char,那可能導致寫入內存出錯(參考這篇http://en.wikipedia.org/wiki/Data_structure_alignment)。

有的同學已經看出來了,如果源指針目標指針都沒對齊,xor結果也是零,那不就錯了么?

OK,不還有一段代碼么,在STRALIGN里面,會對目標字符串指針地址取模,然后將余數返回,比如我們運行時人為地修改s1以及s2地址將其+1。debug運行如下圖,得到p以及str地址,可以看到都是對齊在unsigned long邊界上的( p & 3 一定是0)。


我們在Autos窗口里直接修改地址,讓其加一,如下圖:


這樣兩個指針就都沒有對齊了。繼續運行:


果然如我們預計的retVal的值為0。


xRet返回值為4 – 1,也就是3。


3個字符串(“aaa”)被拷貝到目標字符串里面,這時候目標字符串指針位置是對齊的了。

這是如果有編程經驗的朋友可能已經有疑問,開頭有可能沒對齊,也有可能結尾部分沒對齊啊,也就是尾巴部分一定是4的倍數么?未必,這時候這一段代碼就起作用了。

unsigned long key1 = MKW(0x1ul);

??????? unsigned long key2 = MKW(0x80ul);

運算結果key1是0×01010101,key2結果是0×80808080,如果你看過Tony Bai寫的strlen源碼分析http://bigwhite.blogbus.com/logs/37753065.html ,就會發現這兩個有意思的數字同樣出現在glibc標準庫當中。

((l – key1) & ~l) & key2我就不分析了,可以猜測到,這是對源字符串中NULL結尾符的檢測。當檢測到有結尾符的時候,就做按char拷貝,然后返回。感興趣的可以參考TonyBai那篇文章,然后自己寫幾個test case測試一下。

整個函數就是這樣,分析完畢。

轉載于:https://www.cnblogs.com/lua5/archive/2010/12/09/1901591.html

總結

以上是生活随笔為你收集整理的dietlibc中的strcpy算法浅析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。