在C语言里有一个通用指针,即void*类型指针。通用指针有一条特殊的性质:任何一个指向某种类型(非函数类型)数据的指针转型为通用指针后再转换回原始类型,指针(的值)不会改变。换句话说,任何非函数类型的指针与通用指针间的互相转型(以及赋值)是(语法上)合法且(语义上)安全的。
通用型指针实际是一种类型未知的指针,因此不能对它解引用(dereference)和施行下标(subscripting)操作,也不能把它加加减减。
根据以上描述,下面这段程序
/* fool.c */
void foo(void *p)
{
++p;
}
显然就是非法的。
可是作者在Win2000平台上用gcc -S fool.c(MinGW 3.1.0,其中gcc为3.2.3版本)却顺利编译通过了上述代码,生成的汇编码如下:
_foo:
pushl %ebp
movl %esp, %ebp
incl 8(%ebp)
popl %ebp
ret
注意incl 8(%ebp)这条指令,显然gcc把void*指针当成了char*指针,并对它施行了相应的自增操作(前进一个byte)。真是自作聪明!
大家不要误以为这是gcc为了兼容老程序而有意为之,实际上史前的C根本没有void*型指针,也就不存在所谓兼容问题了。编译器这种不声不响的小动作不太惹人注意,但危险可是大大的,程序员千万要保持警惕!
试试VC6.0,用cl /c fool.c编译,会得到一个"error C2036: 'void *' : unknown size"的错误信息。嗯,这才对头!
这一次Visual C++的表现好于gcc,值得表扬。