1. 未包含头文件引起函数返回值错误
出错代码:
myPointer = umalloc(xxx); if (myPointer) { myPointer->memberA = aaaa; .... }
在64位机器上,运行上面代码, 在执行到第4行的时候会出现段错误。
原因:
在上述代码中, umalloc 是在另一个文件uMem.c 里面定义的, 如下。文件声明在uMem,h中。但是上面的代码并未包含此头文件,在编译时,由于没有包含头文件,umalloc函数被默认为返回类型是int,并产生一个waringing,提示第一行代码有一个警告,将interger强制转换为了Pointer。
void *uMalloc(uint32_t num_bytes) { void *value; value = malloc(num_bytes); if (value == NULL) { return NULL; } memset(value, 0, num_bytes); return value; }
执行时, 在gdb中调试发现umalloc函数里分配的指针值为 0x7fffe800eb40,但是函数返回时被强制转换为了32位的int值0xe800eb40,再赋值给myPointer的时候,再次被转换为64位指针,由32位填充为64位,但这个时候的值变为了0xffffffffe800eb40。在第4行向这个地方赋值时,导致系统崩溃。
此问题在32位系统上运行是没有问题的。
2. 函数参数传递错误
在模块内部定义函数的原型声明为 xxxModuleInit(int maxSize); 在模块外部,在调用的时候,没有传参数进来,直接调用的xxxModuleInit();
由于没有包含头文件,编译器默认该函数参数为void,所以编译到这里,连一个warning都没有,导致到了执行阶段才报错,而且有一定的随机性,有些时候带的垃圾数据刚好执行没问题,但是在下次执行其它地方的代码时才异常,有一定的干扰。
通常C语言并不要求函数一定要在被调用之前定义,编译器在处理到某个未知类型的函数时,会为其创建一个隐式声明,并假设该函数返回值类型为int。但编译器无法检查传递给该函数的实参类型和个数是否正确,所以这不利于编译器为我们排除错误。