void相关的无类型变量在使用时必须强制数据类型转换问题。

来源:互联网 发布:千牛卖家版mac不能用 编辑:程序博客网 时间:2024/05/01 12:54


  • 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 型,所以出现错误。
新编辑帖子中蓝色部分是修正后的,有些错误的已经被删除。这里特别感谢老九,发现了这个错误。


0 0
原创粉丝点击