近期开发代码, 出现了一些诡异现象。追查原因是公司使用的签名函数出现的问题。
问题: 代码使用的签名库函数, 对于<=4字节的字符串, 签名就是本身。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 5 int main(){ 6 char str[128] = "ni"; //长度是2 7 unsigned num[1]; //长度是4 8 memset(num, 0, sizeof(unsigned)); 9 memcpy(num, str, strlen(str)); //num[0] = 26990 10 11 //可以看出, str, num 在前3个字节的内存是相等的 12 printf("tag = %d\n", memcmp(num, str, strlen(str) + 1)); //把\0也算进去 13 14 //对于使用的优化后的签名函数, <= 4个字节则签名为本身(12的签名还是12) 15 //出现的bug是: 16 //str:ni, len:3 ---> sign:26990 17 //num:26990, len:4 ---> sign:26990 18 return 0; 19 }
hash函数只是计算签名, 有时会有hash冲突导致实际不相等的字符串, 有相同的hash值。
如果要严格比较, 可以直接比较内存字节。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 5 int is_eq( 6 const void* addr1, int len1, 7 const void* addr2, int len2){ 8 if (len1 != len2){ 9 return 1; 10 } 11 return memcmp(addr1, addr2, len1) == 0? 0:1; 12 } 13 14 int main(){ 15 char str[128] = "ni"; //长度是2 16 unsigned num[1]; //长度是4 17 num[0] = 26990; 18 19 //把字符串的结尾也计算进去 20 printf("tag = %d\n", is_eq(str, strlen(str) + 1, num, sizeof(num))); 21 return 0; 22 }
在严格场景下, 可以先用hash做签名, 之后再具体到每个hash值(桶, 拉链)上进行内存字节的比较就可以解决。