近日编写项目源码时, 出现局部变量在调用函数接口前后变量值改变的问题. 经过再三调试, 才发现是传参问题. 此问题其实在编译时就会有警告信息, 不过没有加入该选项, 导致没有警告信息, 最终多个平台调试才发现问题所在.
warning: 编译过程中一定要尽量加上警告选项.
编译警告如下:
27_implicitConversions.c:23: warning: passing argument 1 of ‘assignm’ from incompatible pointer type
27_implicitConversions.c:4: note: expected ‘int *’ but argument is of type ‘short unsigned int *’
27_implicitConversions.c:24: warning: passing argument 1 of ‘assignm’ from incompatible pointer type
27_implicitConversions.c:4: note: expected ‘int *’ but argument is of type ‘short unsigned int *’
27_implicitConversions.c:6: warning: dereferencing pointer ‘usNum1.17’ does break strict-aliasing rules
27_implicitConversions.c:23: note: initialized from here
27_implicitConversions.c:6: warning: dereferencing pointer ‘usNum2.18’ does break strict-aliasing rules
27_implicitConversions.c:24: note: initialized from here
错误原理分析:
unsigned short 占16字节, int 占32字节.
unsigned short 在函数中定义两个变量, 两个变量在栈中紧挨着. 分别是:
0xbf9a558c
0xbf9a558e
196615 二进制: 0000 0000 0000 0011 0000 0000 0000 0111
当赋值时, unsigned short = int; 短字节向长字节看齐. 此时unsigned short 变量1获得的值为:
0000 0000 0000 0111. 十进制为: 7.
unsigned short 变量2 再次赋值时, unsigned short 变量2获得的值依旧为:
0000 0000 0000 0111. 十进制为: 7.
但是由于没有强制转换, 而变量1和变量2在栈中是紧挨着的, 所以变量2在赋值时, 会把变量1所在的栈覆盖掉, 覆盖的为高位的16位, 即0000 0000 0000 0011. 所以变量2的值就变为3.
抽象描述如下:
196615 : 0000 0000 0000 0011 0000 0000 0000 0111
变量1: 0000 0000 0000 0111
196615: 0000 0000 0000 0011 0000 0000 0000 0111
变量2: 0000 0000 0000 0111
//源码
#include <stdio.h>
#include <stdlib.h>
int assignm(int *piNum)
{
*piNum = 196615; //binary: 0000 0000 0000 0011 0000 0000 0000 0111
return 0;
}
int main()
{
unsigned short usNum1;
char *pszStr1 = "Hello world";
unsigned short usNum2;
char *pszStr2 = "World peace";
printf("%p\n", &usNum1);
printf("%p\n", pszStr1);
printf("%p\n", &usNum2);
printf("%p\n", pszStr2);
assignm(&usNum1);
assignm(&usNum2);
printf("usNum1 = %u\n", usNum1);
printf("pszStr1 = %s\n", pszStr1);
printf("usNnum2 = %u\n", usNum2);
printf("pszStr2 = %s\n", pszStr2);
return 0;
}
/*运行结果:
0xbf9a558e
0x80486d0
0xbf9a558c
0x80486dc
usNum1 = 3
pszStr1 = Hello world
usNnum2 = 7
pszStr2 = World peace
运行结果*/