深入理解指针类型间的转换

C++中指针的强制转换

强制类型转换(int)、(int&)和(int*)的区别

内存中的地址

  地址的本质就是一串0和1的机器代码,内存中的地址没有明确数据类型,但地址值有类型,以32位编译器为例,内存中的地址是一个32位的整数。无论什么类型的指针变量,在内存中本质上都是一样的,都是一个整数值的地址值,该地址值可以转换为其他类型,比如float或char,但一般不要强转,此时已不再是合法地址而是一个单纯的数据值,除了没有意义外,还会出现数据读取错误(后面会解释)。

int a;

  当我们用a时,由于前面把a定义为int型,则编译器知道从a的地址开始向后取4个字节再把它解释成int型。

指针变量及不同指针类型的含义

(1)指针变量

int *a;

  指针变量,本质上是一个变量,只是它是存放地址的变量,指针的类型代表的是它所指向的变量的类型。因此就有了指向整型、字符型、浮点型等其它类型的指针,但实际上所有类型的指针变量存放的都是int型。

  上述代码表示指向整型的指针变量a,其中a表示一个地址值,上面曾提到地址没有明确的数据类型,因为地址可以为指向整型的指针,可以为指向浮点型的指针。指针类型为整型,表示当我们对该地址进行访问(解引用)时,编译器会将它解释为整型。

  注意:指针地址只指向数据存储的内存的位置,具体变量的类型由编译器告知。

(2)不同类型的指针

  声明不同类型的指针变量既是规定了该变量结合指针运算符时读取内存中的字节数,同样规定了在指针移动和指针的运算时(加、减)在内存中移动的最小字节数。

强制转换的原理

(1)普通变量强转

  (float)a,就是先按照int类型取出该数值,再将该数值按照int to float的规则转换成float型,如果反过来,则会发生数据截断。

(2)指针变量强转

  旧指针 to 新指针的强制类型转换是指将指针所指的内容的类型由原先的类型转换为后面的类型:即进行变量解释的时候,解释的类型变化。

  如果有一个指针p,我们需要把它的类型和所指向的类型改为TYEP*和TYPE,那么语法格式是:(TYPE*)p;这样强制类型转换的结果是一个新指针,该新指针的类型是TYPE*,它指向的类型是TYPE,(也就是说,新指针指向的数据将会用TYPE类型进行解释,如果之前是浮点型数据-3.75,先将其转换为二进制代码,然后转化为TYPE类型存储),它指向的地址就是原指针指向的地址。

  注意:(int &)y,告诉编译器将y当做int看待

 void test02(){

     //-----------------------------
//float指针相关的强制转换
//不同类型的指针变量,在内存中本质上都是一样的,都是一个整数值的地址值,一般表现为8位十六进制数
//不同的类型表示地址指向值的解释类型,及该变量在内存中占据字节的数目
//地址值可以强转为其他类型,但将地址指向值解释为其他类型容易出错,如float解释为int
//常量直接赋值给指针是不可以的,必须强转为合法地址,另外由于内存地址是整型值,因此浮点型数据不能成为合法地址
//-----------------------------
float a = 10.1;
float *p_ = &a; cout << typeid(p_).name() << endl; //float*
cout << p_ << endl; //地址,8位十六进制数字(32位二进制数字)
cout << *p_ << endl; //地址指向的数据,同样为32位二进制数字,按照float进行解释,得到10.1 //cout << (float)p_ << endl; //不允许将地址直接转化为浮点型,但可以间接修改
cout << (char)p_ << endl; //直接将地址转化为字符型
cout << (int)p_ << endl; //直接将地址转化为十进制整型 cout << (int*)p_ << endl; //将地址float *类型转换为int*,后面的解释会发生变化,但地址的十六进制数字不会发生变化
cout << *(int*)p_ << endl; //地址指向的数据,会按照int型进行解释,得到1092721050
cout << (int&)(*p_) << endl; //同样的将数据解释为int型,得到1092721050, 则是告诉编译器将数据看成int对待 cout << *(int*)&p_ << endl; //将地址(8位十六进制数字)转换为十进制,先取p_的地址,然后按照int进行解释
cout << *(float*)&p_ << endl; //将地址(8位十六进制数字)转换为float,先取p_的地址,然后按照float进行解释
cout << *(float*)p_ << endl; //输出10.1 cout << (char*)p_ << endl; //将地址float*类型转换为char*类型,其实地址的十六进制数字不会发生变化,但<<会直接输出指向的字符串
cout << static_cast<const void *>(p_) << endl; //可以这样输出转换为char*后的地址
cout << *(char*)&p_ << endl; //将地址(8位十六进制数字)转换为char,先取p_的地址,然后按照char进行解释
cout << *(char*)p_ << endl; //将数值型数据按照字符类型,这里无法将float解释为char型,但是int型默认可以转换为ASCII码,解释为char型
}

(3)为什么内存中的地址值不能直接转换为float?

  当地址值转换为float时,编译器会有两种转换方式:(1)将整型地址值转换为浮点型;(2)将地址指向的值转换为浮点型,但不知道采用哪一种,需要我们显式地进行转换。

(4)地址值强转后访问的数据错误

  前面提到可以将地址值转为float或char,此时地址值变成了数据(有可能无法解释为char数据),而非合法地址。在对该地址进行访问时,需要将该地址值重新变为合法地址,通过(int*)强转,但浮点型数据不允许作为地址值。

(5)字符强转为合法地址

 void test04(){
char m = 'b';
char *n = "b";
//cout << typeid('b').name() << endl;
float *p0;
int *p1;
float *p2;
float *p3;
p0 = (float*)(&m);
p1 = (int*)(m); //会先转换为m变量的ASCII值,98
p2 = (float*)();
p3 = (float*)(n);
//cout << &(int(m)) << endl;
cout << static_cast<const void *>(&m) << endl;
cout << p0 << endl;
cout << p1 << endl;
//cout << *p1 << endl;//相当于将98强转为合法地址,但并没有对该地址进行初始化,因此直接输出会显示访问冲突
cout << p2 << endl;
cout << p3 << endl;
}

  特别注意:char*类型不能直接由cout输出对应地址,cout会直接输出指向的字符串,可以用static_cast<const void *>(&m)来进行地址输出。

C++指针类型间强制转换的更多相关文章

  1. c++之旅:类型的强制转换

    类型强制转换 在编程的时候我们经常遇到类型的强制转换,C++为此提供了更安全的转换方式,在编程中我们更多的应该采用C++提供的类型转换方式 基本类型转换 基本类型转换用的最多,一般将高精度转换为低精度 ...

  2. C++ 各种基本类型间的转换

    常用的转换方法: 流转换 STL标准函数库中函数转换 流转换 流转换主要是用到了<sstream>库中的stringstream类. 通过stringstream可以完成基本类型间的转换, ...

  3. PHP 变量类型的强制转换 & 创建空对象

    PHP 在变量定义中不需要(或不支持)明示的类型定义:变量类型是根据使用该变量的上下文所决定的. 也就是说,如果把一个字符串值赋给变量 var,var 就成了一个字符串.如果又把一个整型值赋给 var ...

  4. 牛客网Java刷题知识点之基本类型的自动转换和基本类型的强制转换

    不多说,直接上干货! TypeConvertDemo.java //自动类型转换 class TypeConvertDemo { public static void main(String[] ar ...

  5. Python变量类型的强制转换

    当我们需要对数据的类型转换时,只需要将数据类型作为函数名即可. 下面给出的函数可以执行数据类型之间的转换,函数返回一个新的对象,表示转换的值 函数格式 使用示例 描述 int(x [,base]) i ...

  6. int类型被强制转换成较低精度的byte类型

    公司的项目上线之前会进行代码合规性检查,其中很容易违反的一个规则就是“不要把原始类型转换成较低的精度”,实际开发的过程中,很多方法在处理数据时,尤其在做移位操作的时候,难免要把int类型转换成byte ...

  7. C++处理char*,char[],string三种类型间的转换

    前言 在C和C++中,有一个相当重要的部分,就是字符串的编程描述.在学C的时候,很多人习惯了char[],char*表示法,直到遇见了C++后,出现了第三者:string.这时候,很多初学者就会在这三 ...

  8. C语言指针类型 强制转换

    关于C语言指针类型 强制转换  引用一篇文章: C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值.不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个 ...

  9. C++中类型强制转换

    C++中强制类型转换有四种: 1.static_cast 格式:static_cast<Type>(Value); --用于基本类型间的转换,但不能用于基本类型指针间的转换: int i ...

随机推荐

  1. Invalid Rom

    问题描述 原因说明 这多半是因为单片机超频被锁,就是HSE_VALUE设置的与实际值不一致,容易造成这个问题. 解放方法 1. 先正确配置 HSE_VLAUE, 看HSE_VALUE 修改问题. 2. ...

  2. json对象数组的创建、遍历、添加、删除、修改、js的splice()用法

    本文链接:https://blog.csdn.net/houfengfei668/article/details/79843625 )第二种方式:手动构造json对象数组 )for )用splice方 ...

  3. mysql主从复制原理分析

    1.主从复制这类NFS存储数据通过inotify+rsync同步到备份的NFS服务器,只不 过Mysql的复制方案是其自带的工具inotify 是一种文件系统的变化通知机制,如文件增加.删除等事件可以 ...

  4. 2019-8-31-C#-通过编程的方法在桌面创建回收站快捷方式

    title author date CreateTime categories C# 通过编程的方法在桌面创建回收站快捷方式 lindexi 2019-08-31 16:55:58 +0800 201 ...

  5. 【模板篇】A* 寻路算法

    上次在做k短路的时候说到了A*, 但是并没有仔细的研究A*寻路, 毕竟k短路中的A*也不怎么标准… A*寻路的过程网上还是有很多的, 讲得也很清楚, 不妨跟着里面的图示自己动手操作一下, 基本一遍就能 ...

  6. css---6 选择器声明的优先级

    选择器的特殊性由选择器本身的组件确定,特殊性值表述为4个部分,如 0,0,0,0一个选择器的具体特殊性如下确定: 1.对于选择器中给定的ID属性值,加 0,1,0,0 2.对于选择器中给定的各个类属性 ...

  7. COGS2353 【HZOI2015】有标号的DAG计数 I

    题面 题目描述 给定一正整数n,对n个点有标号的有向无环图(可以不连通)进行计数,输出答案mod 10007的结果 输入格式 一个正整数n 输出格式 一个数,表示答案 样例输入 3 样例输出 25 提 ...

  8. P5390 [Cnoi2019]数学作业

    P5390 [Cnoi2019]数学作业求子集异或和的和拆成2进制,假设有x个数这一位为1,剩下n-x个数对答案没有贡献,对于这一位而言,对答案的贡献就是,x个数选奇数个数的方案数*2^(n-x).由 ...

  9. C# 调用 C#DLL

    加载dll-添加引用 添加引用的意思是让程序生成时根据配置的路径去加载相应的dll.其引用的步骤如下图所示: 解决方案->引用-> 添加引用-> 浏览-> 选择dll所在的路径 ...

  10. 使用C++视频播放器库libvlc

    libvlc简介 vlc是一个开源的视频播放器,并提供了库供二次开发,其视频解码库是ffmpeg,网络库是live555.