我正在编写一个例程,在嵌入式(ARM Cortex M0 @ 16MHz)应用程序的指定内存块中找到一个字符串,我想知道为什么我编写的两个不同版本以不同的速度运行。
char* memstr(char* mem, uint32_t n, char* str) {
if( (str[0] == '\0') || (n == 0) ) return NULL;
uint32_t i = 0;
char* max_mem;
max_mem = mem + n;
while( mem < max_mem ) {
if( *mem != str[i] ) {
mem -= i;
i = 0;
} else {
if(str[i+1] == '\0') return mem - i;
i++;
}
mem++;
}
return NULL;
}
char* memstr2(char* mem, uint32_t n, char* str) {
if( (str[0] == '\0') || (n == 0) ) return NULL;
uint32_t c = 0;
uint32_t i = 0;
while( c < n ) {
if( mem[c] != str[i] ) {
c -= i;
i = 0;
} else {
i++;
if(str[i] == '\0') return &mem[c - i + 1];
}
c++;
}
return NULL;
}
当在20到200字节的内存中找到7个字符的字符串时,memstr一直比memstr2快1us。例如,在110字节中找到7个字符的字符串,memstr需要106us,而memstr2需要107us。 1us可能听起来不是什么大问题,但在嵌入式应用程序中,每个蜱都很重要,这是一个缺点。
一种奖励问题:这也促使我编写自己的strstr,它比stock strstr更快(例如,在207字符串中查找7个字符的字符串需要my_strstr 236us和strstr 274us)。这有什么不对,因为strstr必须进行相当优化?
char* my_strstr(char* str1, char* str2) {
uint32_t i = 0;
if( str2[0] == '\0' ) return NULL;
while( *str1 != '\0' ) {
if( *str1 != str2[i] ) {
str1 -= i;
i = 0;
} else {
i++;
if(str2[i] == '\0') return (str1 - i - 1);
}
str1++;
}
return NULL;
}
答案 0 :(得分:0)
首先,如果搜索以两个相等字符开头的字符串,则两个函数都不起作用:如果搜索xxabcde并且字符串包含xxxabcde,那么当您注意到xxabcde与第三个x不匹配时,你已经跳过两个x并且不匹配字符串。
您也不检查是否搜索空字符串,在这种情况下,您的代码会产生未定义的行为。
您将内存与内存进行比较。但是,只需将内存与单个字符进行比较,就可以完成大量的工作。如果您搜索“abcde”,首先必须找到字母a。所以我先检查一个空字符串,然后读取第一个字符。然后首先循环检查该字符。
char first = str2 [0];
if (first == '\0') return mem;
for (; mem < maxmem; ++mem) if (*mem == first) {
... check whether there is a match
}
您应该检查您的数据。如果您希望搜索字符串提前出现而您希望它通常根本不存在,那么您可以编写不同的代码。
答案 1 :(得分:0)
在memstr&#39; mem&#39;用作指针。在memstr2&#39; mem&#39;用作数组的名称&#39; mem [c]&#39;。根据优化,编译器可能会乘以1。
例如在声明中:
if( mem[c] != str[i] ) {
每次循环计算mem [c]为
* ( &mem[0] + c * sizeof(mem[0]) )
一个体面的编译器会发现,对于一个&#39; char&#39; sizeof(mem [0])== 1,可以跳过多个。如果有意禁用优化,就像通常对调试版本所做的那样,我可以想象每个循环有一个额外的乘法运算。即使没有乘法,memstr2版本也会有一些额外的计算时间,但如果可以测量的话会让我感到惊讶。
答案 2 :(得分:-1)
在我看来,差异可能是由于在第二个版本中你从函数返回时取消引用指针(return &mem[c - i - 1];
),这可能导致在内存中访问,这是昂贵的,是在你的第一个函数(mem - i
)中不会发生的事情
但唯一可以确定的是查看为每个案例创建的程序集
我不认为这是关于C而是关于编译器和平台