一、memchr函数
memchr(memory char)是一个标准库函数,用于查找内存块中的一个字节,其函数定义如下:
void *memchr(const void *s, int c, size_t n);
其中,s是需要查找的内存块指针,c是需要查找的字符,n是需要查找的内存块大小。
二、memchr函数的用法
memchr函数可以用于查找一个字符在字符串中的位置。下面是一个示例代码:
char str[] = "hello world";
char *ptr = (char*)memchr(str, 'o', strlen(str));
if (ptr != NULL) {
printf("第一个o的位置是:%ld\n", ptr - str + 1);
}
输出结果:
第一个o的位置是:5
代码解释:首先将一个字符串赋值给字符串数组str,然后将字符'o'作为第二个参数传递给memchr函数,第三个参数是字符串数组str的长度。如果找到了字符'o'的位置,则指针ptr指向该位置,否则指针ptr指向NULL。最后输出字符'o'在字符串中的位置。
三、memchr函数的性能
memchr函数是一种非常高效的查找字符在字符串中的位置的方法,因为它是直接在内存中查找,而不是通过字符串的遍历进行查找。
下面是一个基准测试代码,用于比较memchr函数和字符串遍历法的性能:
#include <stdio.h>
#include <time.h>
#include <string.h>
#define REPEAT 1000000
long current_timestamp() {
struct timeval te;
gettimeofday(&te, NULL);
long milliseconds = te.tv_sec*1000000LL + te.tv_usec;
return milliseconds;
}
int main() {
char str[] = "abcdefghijklmnopqrstuvwxyz";
char *ptr = NULL;
long start, end;
// test memchr
start = current_timestamp();
for (int i = 0; i < REPEAT; i++) {
ptr = (char*)memchr(str, 'z', strlen(str));
}
end = current_timestamp();
printf("memchr: %ld us\n", end - start);
// test travese string
start = current_timestamp();
for (int i = 0; i < REPEAT; i++) {
for (int j = 0; j < strlen(str); j++) {
if (str[j] == 'z') {
ptr = &str[j];
break;
}
}
}
end = current_timestamp();
printf("travese string: %ld us\n", end - start);
return 0;
}
输出结果:
memchr: 33 us
travese string: 1080 us
代码解释:这个测试用例分别测试了memchr函数和字符串遍历法的性能,先构造一个包含26个字符的字符串,然后从中查找字母'z'的位置计时1000000次。可以发现,memchr函数的查找速度非常快,而字符串遍历法的速度相对就比较慢。
四、memchr头文件
memchr函数定义在头文件string.h或strings.h中,因此,需要使用memchr函数时,需要在代码文件中包含这个头文件。
#include <string.h>
五、memchr API
下面是memchr函数的详细API文档:
void *memchr(const void *s, int c, size_t n);
s
- 这是指向源字符串的指针。
c
- 这是要查找的字符。
n
- 这是要查找的前n个字符的长度,也就是源字符串的长度。
该函数返回在内存块s中查找到的字符c的指针,如果未找到字符c,则返回NULL。
六、memchr汇编实现
下面是memchr函数的汇编实现代码:
1 memchr:
2 mov rax, rdi ; rax = s
3 mov ecx, edi ; ecx = c
4 mov edx, esi ; edx = n
5 sub esi, 1 ; n--
6 cmp esi, -1 ; if (n < 0)
7 jb .exit ; return NULL
8 .loop:
9 cmp byte [rax], cl ; if (*s == c)
10 je .found
11 add rax, 1 ; s++
12 dec esi ; n--
13 jnz .loop ; else continue
14 .exit:
15 xor eax, eax ; return NULL
16 ret
17 .found:
18 ret ; return s
代码解释:这个汇编实现会比C代码实现快得多,因为它直接使用了x86_64汇编指令。
七、memchr类似函数选取
除了memchr函数,还有其它类似的函数可以被用来查找内存块中的一个字符。例如:
- strchr: 从字符串中查找一个字符
- strstr: 在字符串中查找一个子字符串
下面是strchr函数的例子:
char * str = "hello world";
char *pch = strchr(str, 'l');
while (pch != NULL) {
printf("l found at %ld\n", pch - str + 1);
pch = strchr(pch + 1, 'l');
}
输出结果:
l found at 3
l found at 4
l found at 10
代码解释:首先将一个字符串赋值为char*类型的指针str,然后调用strchr函数查找字符串中第一个字符‘l’的位置,然后每次循环都通过指针的偏移量再次查找。 strch() 和 memchr() 在用途上相似,但 strchr() 只能查找字符,而 memchr() 能在字节序列中查找任意值。