wcslen 源碼 實現(xiàn) 學習

vscode 連接 wsl 的c調(diào)試 good
2022年5月2日 學了下 strlen 和 wcslen
musl的實現(xiàn)可讀性好陷遮。 glibc 優(yōu)化到了匯編

#include <wchar.h>

size_t wcslen(const wchar_t *s)
{
    const wchar_t *a;
    for (a=s; *s; s++);
    return s-a;
}
//刪掉了一些宏,方便理解。
size_t strlen(const char *s)
{
    const char *a = s; 
    for (; *s; s++);
    return s-a;
}

ulibc的

//strlen.c 
#include "_string.h"
#ifdef WANT_WIDE
# define Wstrlen wcslen
#else
# define Wstrlen strlen
#endif

size_t Wstrlen(const Wchar *s)
{
    register const Wchar *p;

    for (p=s ; *p ; p++);

    return p - s;
}
libc_hidden_weak(Wstrlen)
//ulibc更加簡潔霞溪。 wcslen和strlen 根據(jù)宏來一個方法
//wcslen.c
#define WANT_WIDE
#include "strlen.c"
// http://c.biancheng.net/c/assert/ 
// 在操作指針時,一定要保證在指針有效內(nèi)存空間內(nèi)操作,不然 Segmentation fault  段錯誤咒劲。 被操作系統(tǒng)kill.
// c編譯器內(nèi)置宏 https://zhuanlan.zhihu.com/p/409044316
// ANSI:即 char继薛,可用字符串處理函數(shù):strcat( ),strcpy( ), strlen( )等以str打頭的函數(shù)。
// UNICODE:wchar_t是Unicode字符的數(shù)據(jù)類型爽待,它實際定義在里:
int main(void)
{
    // assert(NULL);
    printf("文件: %s,函數(shù): %s %s %s \n",__FILE__ , __func__,__ASSERT_FUNCTION,__DATE__); //幾個c編譯器內(nèi)置變量
    char destination[25];
    char *blank = " ", *c = "C++", *Borland = "Borland";

    strcpy(destination, Borland);
    strcat(destination, blank);
    strcat(destination, c);

    printf("is: %s\n", strchr(destination, 'a'));
    printf("is2: %s\n", my_strchr(destination, 'a+lskjdsafsfsfa'));
    printf("%s\n", destination);

// 字符串分割 
    char str[80] = "This is - www.runoob.com - website";
    // const char s[2] = "-";
    char* s = "-";
    char *token;
    /* 獲取第一個子字符串 */
    token = strtok(str, s);
    /* 繼續(xù)獲取其他的子字符串 */
    while (token != NULL)
    {
        printf("%s\n", token);
        token = strtok(NULL, s);
    }
//調(diào)用 strcat 必須保證目標地址有足夠的已分配的內(nèi)存用于存儲結果损同。通常需要用 malloc 提前分配內(nèi)存 或 定義一個足夠大的靜態(tài) char[] 。
    // char* one1="hao",one2=" ca";
    char one1[100]="hao";
    // char *one1=malloc(100);
    char* one2=" ca";
    char* one3="ab2行者";  //wcslen本程序是7 . 這里會有各種奇怪長度鸟款。因為wcslen會4個字節(jié)計算一個字符直到遇到0
    char* one4=L"ab2行者";
    char* one5=L"ab2行者6789十了ab"; //超過10行則調(diào)用 xmmm寄存器 wsclen.s 優(yōu)化的匯編...
    // hexdump -C str.c  查看assicc碼 22 是雙引號"
    printf("strcat: %s \n",strcat(one1,one2));
    // printf("%d \n",strlen("wanglaowu"));
    // printf("%d \n",strlen("行者"));  // strlen 計算的是字節(jié) 不是字符膏燃。
    // printf("%d \n",strlen(L"行者")); 
    // printf("%d \n",wcslen(L"行者")); //wsl x64下 調(diào)用的是__wcslen_sse2 用匯編實現(xiàn)的 
    printf("one3 strlen: %d \n",strlen(one3));
    printf("one3 wcslen: %d \n",wcslen(one3));
    printf("one4 strlen: %d \n",strlen(one4));
    printf("one4 wcslen: %d \n",wcslen(one4));
    printf("one5 wcslen: %d \n",wcslen(one5));
    printf("%d \n",wcslen(L"a馮哥2"));
    return 0;
}
// vscode 調(diào)試控制臺 下 gdb 查看內(nèi)存 
// -exec x /10xw 0x5555555560b8
image.png

首先 strlen 和 wcslen 都是遇到內(nèi)存為 0 的時候停止計算
strlen 計算 L 開頭的utf-16(網(wǎng)上一般叫寬字符,實際上是utf-16編碼的) 還是按字節(jié)來數(shù)的何什。 strlen 計算L開頭的字符串就是 1 或 2 组哩。因為4個字節(jié)為一組, 例如 a 就是 62 00 00 00 行 就是 4c 88 00 str 遇到0就停止处渣。
不是L開頭的字符串伶贰,是文件的編碼,現(xiàn)在一般都是utf-8.


d72f2e27f53c9fb0f05361feeecdd8e.png

image.png

printf("z9: %d \n",strlen("xa馮哥2")); // 9 good
上面程序 49拚弧黍衙!后面加上這行輸出。則變?yōu)?了 6. 遇0則止 ....

wcslen.s 匯編代碼 10個字符 40個字節(jié)內(nèi)的 前面幾行優(yōu)化
/home/feng/glibc_source/sysdeps/i386/i686/multiarch/wcslen-sse2.S

#if IS_IN (libc)
# include <sysdep.h>
# define STR    4

    .text
ENTRY (__wcslen_sse2)
    mov STR(%esp), %edx

    cmp $0, (%edx)
    jz  L(exit_tail0)
    cmp $0, 4(%edx)
    jz  L(exit_tail1)
    cmp $0, 8(%edx)
    jz  L(exit_tail2)
    cmp $0, 12(%edx)
    jz  L(exit_tail3)
    cmp $0, 16(%edx)
    jz  L(exit_tail4)
    cmp $0, 20(%edx)
    jz  L(exit_tail5)
    cmp $0, 24(%edx)
    jz  L(exit_tail6)
    cmp $0, 28(%edx)
    jz  L(exit_tail7)

    pxor    %xmm0, %xmm0

    lea 32(%edx), %eax
    lea 16(%edx), %ecx
    and $-16, %eax

    pcmpeqd (%eax), %xmm0
    pmovmskb %xmm0, %edx
    pxor    %xmm1, %xmm1
    test    %edx, %edx
    lea 16(%eax), %eax
    jnz L(exit)

    pcmpeqd (%eax), %xmm1
    pmovmskb %xmm1, %edx
    pxor    %xmm2, %xmm2
    test    %edx, %edx
    lea 16(%eax), %eax
    jnz L(exit)

    pcmpeqd (%eax), %xmm2
    pmovmskb %xmm2, %edx
    pxor    %xmm3, %xmm3
    test    %edx, %edx
    lea 16(%eax), %eax
    jnz L(exit)

    pcmpeqd (%eax), %xmm3
    pmovmskb %xmm3, %edx
    test    %edx, %edx
    lea 16(%eax), %eax
    jnz L(exit)

    and $-0x40, %eax

    .p2align 4
L(aligned_64_loop):
    movaps  (%eax), %xmm0
    movaps  16(%eax), %xmm1
    movaps  32(%eax), %xmm2
    movaps  48(%eax), %xmm6

    pminub  %xmm1, %xmm0
    pminub  %xmm6, %xmm2
    pminub  %xmm0, %xmm2
    pcmpeqd %xmm3, %xmm2
    pmovmskb %xmm2, %edx
    test    %edx, %edx
    lea 64(%eax), %eax
    jz  L(aligned_64_loop)

    pcmpeqd -64(%eax), %xmm3
    pmovmskb %xmm3, %edx
    test    %edx, %edx
    lea 48(%ecx), %ecx
    jnz L(exit)

    pcmpeqd %xmm1, %xmm3
    pmovmskb %xmm3, %edx
    test    %edx, %edx
    lea -16(%ecx), %ecx
    jnz L(exit)

    pcmpeqd -32(%eax), %xmm3
    pmovmskb %xmm3, %edx
    test    %edx, %edx
    lea -16(%ecx), %ecx
    jnz L(exit)

    pcmpeqd %xmm6, %xmm3
    pmovmskb %xmm3, %edx
    test    %edx, %edx
    lea -16(%ecx), %ecx
    jnz L(exit)

    jmp L(aligned_64_loop)

    .p2align 4
L(exit):
    sub %ecx, %eax
    shr $2, %eax
    test    %dl, %dl
    jz  L(exit_high)

    mov %dl, %cl
    and $15, %cl
    jz  L(exit_1)
    ret

    .p2align 4
L(exit_high):
    mov %dh, %ch
    and $15, %ch
    jz  L(exit_3)
    add $2, %eax
    ret

    .p2align 4
L(exit_1):
    add $1, %eax
    ret

    .p2align 4
L(exit_3):
    add $3, %eax
    ret

    .p2align 4
L(exit_tail0):
    xor %eax, %eax
    ret

    .p2align 4
L(exit_tail1):
    mov $1, %eax
    ret

    .p2align 4
L(exit_tail2):
    mov $2, %eax
    ret

    .p2align 4
L(exit_tail3):
    mov $3, %eax
    ret

    .p2align 4
L(exit_tail4):
    mov $4, %eax
    ret

    .p2align 4
L(exit_tail5):
    mov $5, %eax
    ret

    .p2align 4
L(exit_tail6):
    mov $6, %eax
    ret

    .p2align 4
L(exit_tail7):
    mov $7, %eax
    ret

END (__wcslen_sse2)
#endif

還有個差不多的
/home/feng/glibc_source/sysdeps/x86_64/wcslen.S
都是glibc的代碼 .我在 wsl x64 win10 下調(diào)試 遇到的是上面的 sse 優(yōu)化過的匯編荠诬。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琅翻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子柑贞,更是在濱河造成了極大的恐慌望迎,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凌外,死亡現(xiàn)場離奇詭異辩尊,居然都是意外死亡,警方通過查閱死者的電腦和手機康辑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門摄欲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疮薇,你說我怎么就攤上這事胸墙。” “怎么了按咒?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵迟隅,是天一觀的道長。 經(jīng)常有香客問我,道長智袭,這世上最難降的妖魔是什么奔缠? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮吼野,結果婚禮上校哎,老公的妹妹穿的比我還像新娘。我一直安慰自己瞳步,他們只是感情好闷哆,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著单起,像睡著了一般抱怔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嘀倒,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天屈留,我揣著相機與錄音,去河邊找鬼括儒。 笑死绕沈,一個胖子當著我的面吹牛锐想,可吹牛的內(nèi)容都是我干的帮寻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼赠摇,長吁一口氣:“原來是場噩夢啊……” “哼固逗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起藕帜,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤烫罩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后洽故,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贝攒,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年时甚,在試婚紗的時候發(fā)現(xiàn)自己被綠了隘弊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡荒适,死狀恐怖梨熙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刀诬,我是刑警寧澤咽扇,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響质欲,放射性物質(zhì)發(fā)生泄漏树埠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一把敞、第九天 我趴在偏房一處隱蔽的房頂上張望弥奸。 院中可真熱鬧,春花似錦奋早、人聲如沸盛霎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愤炸。三九已至,卻和暖如春掉奄,著一層夾襖步出監(jiān)牢的瞬間规个,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工姓建, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诞仓,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓速兔,卻偏偏與公主長得像墅拭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子涣狗,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容