指针强转和void*
C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值。不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个地址就是硬件访问的依据,而名字只是提供给程序员的一种记住这个地址的方便一点的方法。但是,不同的变量在机器中都是0-1代码,所以,我们不能简单的通过检查一个值的位来判断它的类型。 例如,定义如下: int a; float b; double c; long double d; (假设它们所占的字节分别是4、、、,而且连续存储于某个地址空间,起始地址是100,则我们可以得到如下内存分布) a变量就是由以地址100开始到103结束的4个字节内存空间内的0-1代码组成。b变量则是由以地址104开始到112结束的8个字节内存空间内的0-1代码组成。而在机器中,这些内存都是连续的0-1代码,机器并不知道100~103是整型而104~111是float型,所有这些类型都是编译器告知的。当我们用a时,由于前面把a定义为int型,则编译器知道从a的地址开始向后取4个字节再把它解释成int型。那么(float)a,就是先按照int类型取出该数值,再将该数值按照int to float的规则转换成float型。所以强制类型转换就是按照某个变量的类型取出该变量的值,再按照***to***的规则进行强制转转换。如果是(类型名)常数,则是将该常数按照常数to类型 的规则进行强制转换。 指针也是一个变量,它自己占据一个4个字节的地址空间(由于程序的寻址空间是2^32次方,即4GB,所以用4个字节表示指针就已经能指向任何程序能够寻址到的空间了,所以指针的大小为4字节),他的值是另一个东西的地址,这个东西可以是普通变量,结构体,还可以是个函数等等。由于,指针的大小是4字节,所以,我们可以将指针强制转换成int型或者其他类型。同样,我们也可以将任何一个常数转换成int型再赋值给指针。所有的指针所占的空间大小都是4字节,他们只是声明的类型不同,他们的值都是地址指向某个东西,他们对于机器来说没有本质差别,他们之间可以进行强制类型转换。
指针 to 指针的强制类型转换是指将指针所指的内容的类型由原先的类型转换为后面的类型。 int a = ; int *p = &a; float *p1 = (float*)p; 则p和p1的值都是&a,但是*p是将&a地址中的值按照int型变量进行解释,而*p1则是将&a地址中的值按照float型变量进行解释。 鉴于指针之间这种灵活的强制类型转换的需求和出于简化代码的考虑,ANSI C引入了空指针即void*。void指针又名万能指针,在现在的很多程序中,当参数不确定时就用万能指针代替,这一类的指针在线程\进程函数里特别常见。 ANSI C规定,void指针可以复制给其他任意类型的指针,其他任意类型的指针也可以复制给void指针,他们之间复制不需要强制类型转换。当然任何地址也可以复制给void型指针。我们在《网络编程》中经常会看到accept(socket, (struct sockaddr *)&saddr_c, &lenth)之类的语句在&saddr_c之前需要增加代码(struct sockaddr *)是因为当此函数被设计的时候ANSI C还没有提出void*的概念。所有的地址统一用struct sockaddr类型标识,该函数的第二个参数也是指向struct sockaddr类型的指针,此处是强制类型转换。 当然,在某些编译器中不同类型的指针也可以进行直接赋值,但一般情况下会给出类型不匹配的警告。要求程序员显示的给出指针强制类型转换可以提醒程序员小心使用指针,对于明确程序目的具有一定的好处。 、指针类型强制转换: int m; int *pm = &m; char *cp = (char *)&m; pm指向一个整型,cp指向整型数的第一个字节 、结构体之间的强制转换 struct str1 a; struct str2 b; a=(struct str1) b; //this is wrong a=*((struct str1*)&b); //this is correct 、关于一个程序的解释 int main(void) { int a[] = {, , , }; int *ptr1=(int *)(&a+); int *ptr2=(int *)((int)a+); int *c = *(a + ); printf("%x, %x,%x\n", ptr1[-], *ptr2,*c); return ; } 输出分别为4 和2000000, 式子&a+1表示的是指针加法运算,而不是普通的数值加法运算 vs2008下,其中a = 0x001bfc18
(&a + ) = 0x001bfc28
而 a+ = 0x001bfc1c &a + 的值取决于a的类型如果a申明int a;
则&a + = 0xFFFF5704 = a +
如果 int a(ArryLen);
则&a + = 0xFFFF5700 + * ArryLen <> a + a 表示数组的起始地址,(int ) a 表示将a的地址转化为一个整形数,(int)a + 表示普通的数值加法运算,(int *)((int)a + )表示把(int )a + 1转化为整型指针的地址。该地址指向数组a()的第一个字节(从0计数),因为是int型的 所以需要四个字节的解释,所以结果是a()的后三个字节和a()的第一个字节组成的值,该值受大小端的影响。 *(a + ) 此时的a已经是一个常指针了,这个表达式计算出a所指向元素后面的第2个元素的地址,然后对它解引用得到相应的值。这个表达式等价于 int last = a[] 在贴 下面一段代码: 复制代码
#include <stdio.h> typedef struct stu1{
char chs[];
};
typedef struct stu2{
char chs[];
int n;
}; int main(int argc, char const *argv[]){
struct stu1 s1;
struct stu2 s2;
s1.chs[] = 'a';
s1.chs[] = 'b';
s1.chs[] = 'c';
s1.chs[] = 'd';
s1.chs[] = 'e';
s2 = *((struct stu2 *)&s1);
printf("%c\n", s1.chs[]);
printf("%d\n", s2.n);
return ;
}
复制代码
结果输出: d 所有类型 都系统底层的本质都是一样的 都是内存中的 1组成。基本强制类型转换就是 把高出的 部分 位 截取掉。int型数值赋给char型变量时,只保留其最低8位,高位部分舍弃 在看一段代码: 复制代码
#include <stdio.h> typedef struct stu1{
int m;
int n;
};
typedef struct stu2{
char c1;
char c2;
};
int main(int argc, char const *argv[]){
struct stu1 s1;
struct stu2 s2;
s1.m = ; //11 00101111
s1.n = ;
s2 = *((struct stu2 *)&s1);
printf("%d, %d, \n", s2.c1, s2.c2);
int a = ; //10 00101111
char c = (char)a;
printf("%d\n", c);
s1.m = ;
s2 = *((struct stu2 *)&s1);
printf("%d, %d, \n", s2.c1, s2.c2);
return ;
}
复制代码
输出结果: , , , ,
上面代码中 stu1结构体的大小为 4个字节 ,而stu2结构体的大小为 2个字节 ,所以stu1转换为stu2的时候,只保留 前面2 个字节。s1.m 为 int 类型 s2.ch1 为 char 类型,前面说过 int型数值赋给char型变量时,只保留其最低8位,高位部分舍弃 我们可以看出 和 的 后(低)八位(一个字节) 都是一样的 。剩余一个字节(s1.m的高八位) 在赋值给 s2.ch2 815和 559的高八位 不一样 所以输出的结果也不一样。 C语言 指针之间的 强制转换 就是 其指针所指内容之间的 强制转换。一个字节 一个字节之间的转换。多出的部分截取掉。
指针强转和void*的更多相关文章
- 不要伤害指针(5)--void和void指针详解
原文转载地址:http://blog.csdn.net/sunchaoenter/article/details/6587426 增加自己的想法,作为笔记. 1.概述 许多初学者对C/C++语言中的v ...
- 函数指针-如何理解typedef void (*pfun)(void)
问题: 在刚接触typedef void (*pfun)(void) 这个结构的时候,存在疑惑,为什么typedef后只有一"块"东西,而不是两"块"东西呢?那 ...
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6786239 Android 系统的运行时库层代 ...
- ZT自老罗的博客 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 分类: Android 2011-09-23 00:59 31568人阅读 评论(42) 收藏 举报 androidclass ...
- 你必须知道的指针基础-7.void指针与函数指针
一.不能动的“地址”—void指针 1.1 void指针初探 void *表示一个“不知道类型”的指针,也就不知道从这个指针地址开始多少字节为一个数据.和用int表示指针异曲同工,只是更明确是“指针” ...
- int (*(*fp)(void *))[10]; 指向函数的指针类型
<pre lang="c" escaped="true">int (*(*fp)(void *))[10]; //这个类型用typedef分解出来 ...
- NULL指针 Void* 和野指针
在C和C++的语言中常常有这几个概念: NULL指针.空指针.Void *指针.野指针(Wild Pointer)甚至垂悬指针(Dangling Pointer). 1.NULL指针,一般用于指向一个 ...
- 浅谈 “空指针、野指针、void*”
Author: JW. Zhou Date: 2014/7/2 一.空指针(0/NULL) 返回NULL和返回0是完全等价的,因为NULL和0都表示空指针,换句话说:空指针是什么,就是 ...
- 二维指针*(void **)的研究(uC/OS-II案例) 《转载》
uC/OS-II内存管理函数内最难理解的部分就是二维指针,本文以图文并茂的方式对二维指针进行了详细分析与讲解.看完本文,相信对C里面指针的概念又会有进一步的认识. 一.OSMemCreate( ) 函 ...
随机推荐
- 集合框架学习之Guava Collection
开源工具包: Guava : Google Collection Apache:Commons Collecton 1.1 Google Collections Guava:google的工程师利用传 ...
- dateset是不是在缓存中
C#开发erp系统的时候有一个多表数据的查询展示到页面,采用了存储过程的方式,但是存储过程中没有加入分页(菜比).刚开始测试数据几百条没有问题,当数据量提升至十万级后页面加载速度就很卡了,一般是使用分 ...
- 以OpenGL方式运行Unity
Unity在Windows上默认以DirextX的方式运行,在MacOS和Linux上默认以OpenGl的方式运行, 如果希望在Windows上以OpenGL的方式运行可以在命令行中输入 -force ...
- 20141113--SQL 事务
---------------------触发器----------------------------- --触发器本质上还是一个存储过程,trigger --只不过不是通过exec调用执行,而是通 ...
- Python 字典(Dictionary) setdefault()方法
描述 Python 字典(Dictionary) setdefault() 函数和get()方法类似, 如果键不已经存在于字典中,将会添加键并将值设为默认值. 语法 setdefault()方法语法: ...
- MATLAB 生成 COM 步骤
环境: 操作系统:windows xp sp3 MATLAB:Version 7.1.0.246(R14) Service Pack 3 第一步:安装编译器(如果已经安装则可跳过此步) 在MATLAB ...
- 《Java核心技术与最佳实践》读书笔记
第一章 Java7新语法 1.switch中使用字符串 2.增加二进制表示0b10101010:数字字面量允许直径使用下划线12_34_90 3.一个catch字句捕获多个异常,多个异常之间用|分隔 ...
- 打造自己的3D全景漫游
three.js 示例: 打造H5里的"3D全景漫游"秘籍 - 腾讯ISUX QQ物联星球计划 通过pano2vr直接将鱼眼全景图生成立体空间的六个面:也可通过Photos ...
- php错误收集
1.Notice: Undefined offset: 1 in F:\www\my\test.php on line 39,原因offset:接下去的数字是出错的数组下标,一般是超出了数组的取值范围 ...
- 2013-07-23 IT 要闻速记快想
### ========================= ###苹果的新动向今天华尔街日报称,苹果正在测试13英寸的大号iPad,以及更大屏幕的iPhone.而早在五月份,韩国资讯网站 ET New ...