- const char str[] = "CredO~";
- unsigned int int32 = 0x80;
- char ch = '?';
- void *args[] = {(void*)str,(void*)&int32,(void*)&ch};
- ...........这里省略一步将args强制转换成char * 型的过程...........
- putnum((unsigned int)*args[1]);/*putnum就是一个输出值的封装*/
今晚上我的同学要我看个代码,说无法解决,让我看下。具体问题就在上面的代码。
问题描述:int32 = 0x11时,代码执行正确,但测试int32 = 0xaa;就是错误的,输出结果很奇怪,在数据前面填充了数据,变成了0xffffffaa。
我拿到代码看了好一会,并调试运行了下,发现确实是这样的。只要数据最高位为“1”输出就是错误的,也就是和最高位有关系。最高位一般只表示符号位,但现在是无符号变量,这就有点难以理解了。
判断:由于不存在语法错误,指针的使用也没有问题,那就只能是数据类型的问题了。
尝试一: 将变量从无符号改为有符号,错误依旧,额~~~
尝试二:在指针取值前先进行强制类型转换。
- *(unsigned int *)args[1])
尝试是正确的,也就是说和指针变量的类型有关,在使用时必须将void * 型指针变量转换成一个有具体 (并且是正确的)数据长度的类型。
虽然解决方法有了,但是原因还不明确,只能反汇编看看了
- /*原始的方式*/
- q = *args[1];
- 401460: 0f be 00 movsx eaxBYTE PTR [eax]
- /* p = *(unsigned int*)args[1];*/
- putnum((unsigned int)q);
- 401463: 89 04 24 mov DWORD PTR [esp],eax
- 401466: e8 f5 fe ff ff call 401360 <putnum>
- 40146b: e9 70 ff ff ff jmp 4013e0 <ezprintf+0x10>
- /*强制转换后的方式*/
- /* q = *args[1];*/
- p = *(unsigned int*)args[1];
- 401460: 8b 00 mov eax,DWORD PTR [eax]
- E:/C/new 2.c:53
- putnum((unsigned int)p);
- 401462: 89 04 24 mov DWORD PTR [esp],eax
- 401465: e8 f6 fe ff ff call 401360 <putnum>
从加红的结果很明显能够看出,问题在于: 没有进行正确的数据类型转换,void * 转换成 char *(正确的转换类型应该是int *);所以当一开始的数据的最高位为1(单字节的第7位,例如:b000000001xxxxxxx)时,就被当做符号位进行了符号位扩展,出现输出数据前面被填充的现象(变为:b111111111xxxxxxx)。
结论: void型相关变量, 在具体使用(和值相关)时必须进行类型强制转换(并且是要正确的,符合逻辑的),以明确变量的数据长度,否则出现错误:
1、无法编译通过(数据类型不匹配);
2、得到错误的数据(逻辑上有问题)。
2014.3.23
说明:在原来的帖子中,我说的是由于void * 没有经行类型强制转换,编译器默认为 char *,这是一个很大的错误。在这里指出说明(这个转换是在其他代码中有动作)。出现问题的现象,是由于强制类型转换的不合理,原变量是int 型,而在使用时数据被转换成char 型,所以出现错误。
新编辑帖子中蓝色部分是修正后的,有些错误的已经被删除。这里特别感谢老九,发现了这个错误。