斯坦福大学公开课《编程范式》中讲到用C语言实现泛型的linear search。其中的比较函数为void (*cmpfn)(void* vp1, void* vp2)。那么,如果是比较两个字符串数组,该如何写这个比较函数呢?
一般思路都没啥神奇的地方,将void* 类型转换成想要的类型,然后已知类型的比较就可以了。
int str_comp(void* vp1, void* vp2)
{
char* str1 = *(char**) vp1;
char* str2 = *(char**) vp2;
// do something with str1 and str2 ...
}
那么问题就来了,为什么要采用*(char**) 方式, 而不是(char*)方式呢?后者还有因为编译器的支持,可以省略书写的特性(观察前面一个int的例子就是如此)。
视频中的教授讲得很清楚。*(char**)形式是有一步跳跃的,而(char*)显然没有。我们把前者展开成完整形式:*((char**)vp1+0)。表示将vp1看成一个数组的话,第0号元素的内容(是一个char*类型)。
概念太抽象,举个具体的例子:
char* str1 = "hello";
char* str2 = "world";
str_comp(&str1, &str2);
在函数中如何做类型转换呢?
我们传入的很显然是一个char** 变量。那么,通过*(char**) vp1 或者 ((char**)vp1)[0] 形式就可以获得“hello” 字符串的首地址。而(char*)获得是什么呢?
假设“hello”的首地址为1000,&str1 的值为2000,那么vp1的值是2000(形参实参自行脑补),(char*) vp1 的值显然还是2000,*((char*) vp1+0) 的值为1000拆成4个char所显示的第一个byte,以此类推。可以想象最终打印出来的字符串是(char*)1000后面跟一串乱码。