vscode 连接 wsl 的c调试 good
2022年5月2日 学了下 strlen 和 wcslen
musl的实现可读性好。 glibc 优化到了汇编
#include
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 根据宏来一个方法
//wcslen.c
#define WANT_WIDE
#include "strlen.c"
// http://c.biancheng.net/c/assert/
// 在操作指针时,一定要保证在指针有效内存空间内操作,不然 Segmentation fault 段错误。 被操作系统kill.
// c编译器内置宏 https://zhuanlan.zhihu.com/p/409044316
// ANSI:即 char,可用字符串处理函数:strcat( ),strcpy( ), strlen( )等以str打头的函数。
// UNICODE:wchar_t是Unicode字符的数据类型,它实际定义在里:
int main(void)
{
// assert(NULL);
printf("文件: %s,函数: %s %s %s \n",__FILE__ , __func__,__ASSERT_FUNCTION,__DATE__); //几个c编译器内置变量
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);
/* 继续获取其他的子字符串 */
while (token != NULL)
{
printf("%s\n", token);
token = strtok(NULL, s);
}
//调用 strcat 必须保证目标地址有足够的已分配的内存用于存储结果。通常需要用 malloc 提前分配内存 或 定义一个足够大的静态 char[] 。
// char* one1="hao",one2=" ca";
char one1[100]="hao";
// char *one1=malloc(100);
char* one2=" ca";
char* one3="ab2行者"; //wcslen本程序是7 . 这里会有各种奇怪长度。因为wcslen会4个字节计算一个字符直到遇到0
char* one4=L"ab2行者";
char* one5=L"ab2行者6789十了ab"; //超过10行则调用 xmmm寄存器 wsclen.s 优化的汇编...
// hexdump -C str.c 查看assicc码 22 是双引号"
printf("strcat: %s \n",strcat(one1,one2));
// printf("%d \n",strlen("wanglaowu"));
// printf("%d \n",strlen("行者")); // strlen 计算的是字节 不是字符。
// printf("%d \n",strlen(L"行者"));
// printf("%d \n",wcslen(L"行者")); //wsl x64下 调用的是__wcslen_sse2 用汇编实现的
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 调试控制台 下 gdb 查看内存
// -exec x /10xw 0x5555555560b8
首先 strlen 和 wcslen 都是遇到内存为 0 的时候停止计算
strlen 计算 L 开头的utf-16(网上一般叫宽字符,实际上是utf-16编码的) 还是按字节来数的。 strlen 计算L开头的字符串就是 1 或 2 。因为4个字节为一组, 例如 a 就是 62 00 00 00 行 就是 4c 88 00 str 遇到0就停止。
不是L开头的字符串,是文件的编码,现在一般都是utf-8.
printf("z9: %d \n",strlen("xa冯哥2")); // 9 good
上面程序 4!!后面加上这行输出。则变为 了 6. 遇0则止 ....
wcslen.s 汇编代码 10个字符 40个字节内的 前面几行优化
/home/feng/glibc_source/sysdeps/i386/i686/multiarch/wcslen-sse2.S
#if IS_IN (libc)
# include
# 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 下调试 遇到的是上面的 sse 优化过的汇编。