指针强转和void*

C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值。不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个地址就是硬件访问的依据,而名字只是提供给程序员的一种记住这个地址的方便一点的方法。但是,不同的变量在机器中都是0-1代码,所以,我们不能简单的通过检查一个值的位来判断它的类型。

例如,定义如下:

int a;

 float b;

double c;

 long double d;

(假设它们所占的字节分别是4、8、8、10,而且连续存储于某个地址空间,起始地址是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 = 1;

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类型的指针,此处是强制类型转换。

当然,在某些编译器中不同类型的指针也可以进行直接赋值,但一般情况下会给出类型不匹配的警告。要求程序员显示的给出指针强制类型转换可以提醒程序员小心使用指针,对于明确程序目的具有一定的好处。

1、指针类型强制转换:

int m;

int *pm = &m;

char *cp = (char *)&m;

pm指向一个整型,cp指向整型数的第一个字节

2、结构体之间的强制转换

struct str1 a;

struct str2 b;

a=(struct str1) b;                  //this is wrong

a=*((struct str1*)&b);         //this is correct

3、关于一个程序的解释

int main(void)

{

    int a[4] = {1, 2, 3, 4};

    int *ptr1=(int *)(&a+1);

    int *ptr2=(int *)((int)a+1);

    int *c = *(a + 1);

    printf("%x, %x,%x\n", ptr1[-1], *ptr2,*c);

    return 0;

}

输出分别为4 和2000000,2

式子&a+1表示的是指针加法运算,而不是普通的数值加法运算

vs2008下,其中a = 0x001bfc18
(&a + 1) = 0x001bfc28
而 a+1 = 0x001bfc1c

 &a + 1 的值取决于a的类型如果a申明int a;
则&a + 1 = 0xFFFF5704  = a + 1
如果 int a(ArryLen);
则&a + 1 = 0xFFFF5700 + 4 * ArryLen <> a + 1

a 表示数组的起始地址,(int ) a 表示将a的地址转化为一个整形数,(int)a + 1 表示普通的数值加法运算,(int *)((int)a + 1)表示把(int )a + 1转化为整型指针的地址。该地址指向数组a(0)的第一个字节(从0计数),因为是int型的 所以需要四个字节的解释,所以结果是a(0)的后三个字节和a(1)的第一个字节组成的值,该值受大小端的影响。

 *(a + 1)  此时的a已经是一个常指针了,这个表达式计算出a所指向元素后面的第2个元素的地址,然后对它解引用得到相应的值。这个表达式等价于

int last = a[1]

在贴 下面一段代码:

复制代码
#include <stdio.h>

typedef struct stu1{
    char chs[5];
};
typedef struct stu2{
    char chs[4];
    int  n;
};

int main(int argc, char const *argv[]){
    struct stu1 s1;
    struct stu2 s2;
    s1.chs[0] = ‘a‘;
    s1.chs[1] = ‘b‘;
    s1.chs[2] = ‘c‘;
    s1.chs[3] = ‘d‘;
    s1.chs[4] = ‘e‘;
    s2 = *((struct stu2 *)&s1);
    printf("%c\n", s1.chs[3]);
    printf("%d\n", s2.n);
    return 0;
}
复制代码
结果输出:

1 d
2 101
所有类型 都系统底层的本质都是一样的 都是内存中的 0 1组成。基本强制类型转换就是  把高出的 部分 位  截取掉。int型数值赋给char型变量时,只保留其最低8位,高位部分舍弃

在看一段代码:

复制代码
 1 #include <stdio.h>
 2
 3
 4 typedef struct stu1{
 5     int m;
 6     int n;
 7 };
 8 typedef struct stu2{
 9     char c1;
10     char c2;
11 };
12 int main(int argc, char const *argv[]){
13     struct stu1 s1;
14     struct stu2 s2;
15     s1.m = 815;  //11 00101111
16     s1.n = 600;
17     s2 = *((struct stu2 *)&s1);
18     printf("%d, %d, \n", s2.c1, s2.c2);
19     int a = 559; //10 00101111
20     char c = (char)a;
21     printf("%d\n", c);
22     s1.m = 559;
23     s2 = *((struct stu2 *)&s1);
24     printf("%d, %d, \n", s2.c1, s2.c2);
25     return 0;
26 }
复制代码
输出结果:

47, 3,
47
47, 2,
上面代码中 stu1结构体的大小为 4个字节 ,而stu2结构体的大小为 2个字节 ,所以stu1转换为stu2的时候,只保留 前面2 个字节。s1.m 为 int 类型 s2.ch1 为 char 类型,前面说过 int型数值赋给char型变量时,只保留其最低8位,高位部分舍弃

我们可以看出 815  和 559  的 后(低)八位(一个字节) 都是一样的 47。剩余一个字节(s1.m的高八位) 在赋值给 s2.ch2  815和 559的高八位  不一样 所以输出的结果也不一样。  

C语言 指针之间的 强制转换 就是 其指针所指内容之间的 强制转换。一个字节  一个字节之间的转换。多出的部分截取掉。
时间: 2024-08-28 14:42:52

指针强转和void*的相关文章

不要伤害指针(5)--void和void指针详解

原文转载地址:http://blog.csdn.net/sunchaoenter/article/details/6587426 增加自己的想法,作为笔记. 1.概述 许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧. 2.void的含义 void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据. void几乎只有“注释

Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6786239 Android 系统的运行时库层代码是用C++来编写的,用C++来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃.不过系统为 我们提供了智能指针,避免出现上述问题,本文将系统地分析Android系统智能指针(轻量级指针.强指针和弱指针)的实现原理. 在使用C++来编写代码的过程中,指针使用不当造成

void* 指针有什么用

void*其实可以理解为一个context,利用它可以很好的实现C语言面向对象编程.我觉得使用void*,不是为了看起来合适,而是一个约定,使用C/C++编程的人员看到void*,习惯性的就会认为--这是个私有数据,只有定义的一方才有权解释:这也是我们在回调函数中传递void*作为userdata的基础共识. void*指针其实可以用作泛型,你想象一下你在C中要交换两个变量,如果是两个整数的话,就像: void swap_int(int* lhs, int* rhs) { int tmp = *

int (*(*fp)(void *))[10]; 指向函数的指针类型

<pre lang="c" escaped="true">int (*(*fp)(void *))[10]; //这个类型用typedef分解出来 // 第一步:此指针是一个指向函数T1的指针typedef int (*T1(void *))[10];T1 *fp; // 第二步:T1 是一个函数,返回值是T2,参数为(void *)typedef int (*T2)[10];typedef T2 T1(void *);T1 *fp; // 第三步:T2

你必须知道的指针基础-7.void指针与函数指针

一.不能动的“地址”—void指针 1.1 void指针初探 void *表示一个“不知道类型”的指针,也就不知道从这个指针地址开始多少字节为一个数据.和用int表示指针异曲同工,只是更明确是“指针”. 因此void*只能表示一个地址,不能用来&取值,也不能++--移动指针,因此不知道多少字节是一个数据单位. int nums[] = {3,5,6,7,9}; void* ptr1 = nums; //int i = *ptr1; // 对于void指针没法直接取值 int* ptr2 = (i

void指针

1回顶部 热门文章:C++中extern “C”含义深层探索 编程实现盗2005版QQ源码 1.概述 许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧. 2.void的含义 void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据. void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量,让我们试

SGI STL 函数static void (* set_malloc_handler(void (*f)()))()与函数指针解析

在C++ STL的SGI实现版本中,一级空间配置器class __malloc_alloc_template中有一个静态函数的实现如下: static void (*set_malloc_handler(void (*f)()))() { void (*old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = f; return (old); } 没接触过函数指针的人看到这段代码可能会很头疼,不知道这个函数表达什么意思.

浅谈 “空指针、野指针、void*”

        Author: JW. Zhou Date: 2014/7/2 一.空指针(0/NULL) 返回NULL和返回0是完全等价的,因为NULL和0都表示空指针,换句话说:空指针是什么,就是一个被赋值为0的指针,在没有被具体初始化前,其值为0:NULL 是一个标准规定的宏定义,用来表示空指针常量. #define NULL 0   或者 #define NULL ((void*)0) 判断一个指针是否为空指针: f(!p) 和 if(p == NULL) ,if(NULL == p)

C++之智能指针20170920

/******************************************************************************************************************/ 一.C++智能指针_自己实现智能指针 1.使用局部变量结合new的方式,防止new导致的内存泄漏 class sp { private: Person *p; public: sp() : p(0) {}//表明sp的构造函数 继承person的无参构造函数 sp(