博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C---int和指针转换注意事项
阅读量:4221 次
发布时间:2019-05-26

本文共 2484 字,大约阅读时间需要 8 分钟。

这个标题也许写的有点不知所以然了,其实博主今天要讨论的自己在复习c/c++指针和引用的时候遇到的一些问题,慢慢说来…..

开始的时候写了这么一段代码:

int a = 1;int* p = &a;printf("指针变量p的值 p - 16表示  是 = %p \n",p);    printf("a的地址 p - 16表示  是 = %p \n",&a);/*输出指针变量p的值 p - 16表示  是 = 0x7fff375272a0a的地址 p - 16表示  是 = 0x7fff375272a0*/

输出的结果是一样的,也就是说明指针变量p的值 == a的地址

之后我继续写了一段:

printf("指针变量p的值 x - 16表示  是 = %x\n",p);/*输出指针变量p的值 x - 16表示  是 = 375272a0*/

%x是输出一个数的十六进制格式表示,我们可以看出来得到的输出有点相像,只不过%p的输出多了前面一部分,0x是十六进制的标志,后面的f表示16进制中的15,多次输出发现只有后8位是一直没变的,前面的4位总是变化(确切的说是第四位)。

它变化的范围最大是7fff(111111111111111),15位,也就是还剩下17位是没变的。这里我猜的是它的编码规则变了,当后面的32位改变的时候,前面的4位中最后的那一位会根据后32位的大小作相应改变,具体是什么我也不知道。也很有可能我这个想法是错误的,还请知道的朋友指正出来,感激不尽。

那无论我们猜的对不对,有一点是对的,我们不能像32位中一样随随便便将int 和指针类型改变了,比如如下代码

int a = 1;int p = &a;printf("%d\n",*((int*)p));/*在64位下输出错误32位下输出a的值 1*/

因为64位中,我们若强制将一个32位的变量转换成64位,不仅仅是在前面加一段32bit的数据,而是像我上面想的那样改变了编码规则。这样一来就没法根据int*的地址值来寻址了,因为这个地址的值已经不是原来的32位值了,它被改变了。为了证明这一点,我用32位gcc编译了同一段代码。

int a = 0;int* p = &a;int p1 = &a;printf("p1的值(p - 16)是 %p\n",p1);printf("p1的值(x - 16)是 %x\n",p1);printf("指针变量p的值 p - 16表示  是 = %p\n",p);printf("p1的值转换成void*型(p - 16)是 %p\n",(void*)p1);printf("p1的值转换成int *型(p - 16)是 %p\n",(int*)p1);/*32位输出p1的值(p - 16)是 0xffa60b38p1的值(x - 16)是 ffa60b38指针变量p的值 p - 16表示  是 = 0xffa60b38p1的值转换成void*型(p - 16)是 0xffa60b38p1的值转换成int *型(p - 16)是 0xffa60b38*//*64位输出p1的值(p - 16)是 0xa33e0530p1的值(x - 16)是 a33e0530指针变量p的值 p - 16表示  是 = 0x7ffea33e0530p1的值转换成void*型(p - 16)是 0xffffffffa33e0530p1的值转换成int *型(p - 16)是 0xffffffffa33e0530*/

这里32位下得到的结果int*型和int型是完全一样的。排除编译器限制严谨程度,int和指针变量类型是可以互相转换的。但是最好别这么做,在这里这么做只是为了了解指针的实质。

64位下就大不相同了,同一个地址的%p是使用64位的编码规则输出一个32位地址,前面的8位变了。若是直接强制地址转换就会将前32位都填充1,这和下面的visual studio恰好相反。

之后在win7下用visual studio,x_64编译执行了一遍,可以对比一下两者

这里写图片描述

这里可以看出来,在visual studio x64平台上编译得到的结果是不同于gcc 64位的,就指针地址而言,gcc上面的变化是编译器自定的规则,我们无从得知,在vs下可以看出来是直接在前面补上了32位的0,也就是说有效值是完全一样的。

那我们可以知道为什么不能直接对64位平台下的int型转换成指针型来寻址了,因为很可能就是指针的有效值改变了,那寻址就完全失败了,有一行这样的代码都能直接导致整个程序的崩溃。

而在32位下是没更多空间去改变值,大家都是4个字节空间,编码规则一样,所以32位平台下是可以将指针和int型互相转换的,一般不会产生危险(像vs中32位平台,它编译器不允许你将一个指针型赋给一个int型)

综合以上所有:

%x的作用仅仅是将一个整数以32位无符号十六进制输出,它是int型的输出,在32位或64位平台都是4个字节

%p可以看做是输出的指针地址的(值+标识),可能不同情况下是这个标识(让系统识别这是个指针)不一样。

如果是值方面,32位下是一样的,同时强制转换没多余的空间改变值,也就都是一样的。在这种情况下,单对值进行指针类型转换再取地址是可以的,例如int p = &a; *((int*)p)这个就是将int型p转成int*型,值本身一样,加上标识,再取地址,就是a的值了。64的话就是分配地址的时候就不仅仅是后32位有效值了,它根据不同的规则(有可能只是填充0,这种情况有效值不变)来重定义一个32位值,所以大体上是值变了,再加上强制转换类型也都是有自己的规则,填充0或者1,这两者都导致不能直接将32位的整形转换成64位指针型。

为了保证程序的安全性和稳定性,最好不要写这样仅仅针对某个平台可以安全转换类型的代码,应该考虑到多个平台,或者说尽量不使用这样的代码。

总结:

在使用到强制类型转换的时候需要多注意转换的实质

有什么错误还请指出,谢谢。

你可能感兴趣的文章
Spring定时器的时间表达式
查看>>
fastdfs简介
查看>>
主键和唯一索引的区别
查看>>
linux下使用yum安装gcc详解
查看>>
aclocal安装依赖的库
查看>>
String和常量池值的变化
查看>>
FastDFS 安装及使用详解
查看>>
ERROR 1045 (28000): Access denied for user root@localhost (using password: NO)解决方案
查看>>
Host 'XXX' is not allowed to connect to this MySQL server解决方案
查看>>
corosync pacemaker 配置高可用集群(一)
查看>>
5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO
查看>>
nginx(一) nginx详解
查看>>
nginx(二) nginx编译安装 及 配置WEB服务
查看>>
nginx(三) nginx配置:反向代理 负载均衡 后端健康检查 缓存
查看>>
nginx(四) nginx+keepalived 实现主备+双主热备模型的高可用负载均衡代理服务
查看>>
jQuery核心--多库共存
查看>>
QTP Tutorial #23 – QTP Smart Object Identification, Sync Point, and Test Result Analysis
查看>>
第一章漫话自动化测试
查看>>
第二章:Selenium IDE应用实践
查看>>
第三章:Python基础
查看>>