鱼C论坛

 找回密码
 立即注册
查看: 4440|回复: 3

急求 !!!!关于指针之间的强制转换 求解

[复制链接]
发表于 2013-7-1 22:14:30 | 显示全部楼层 |阅读模式
30鱼币
本帖最后由 Skuone 于 2013-7-1 22:28 编辑

首先指针是一个地址,假如说有二个不同类型的指针int 型  float 那他的地址又是怎么样的呢? 是不是只是分配的内存空间长度不同?

假如定义一个句柄类型的指针。M。

另外有一个DWORD类型的指针 N  ,    将返回值为一个地址的函数first的返回值赋给N。

然后进行如下的指针强制转换:

       M =  (N*)N

到底是什么会变。           为什么要转换? 只是内存空间存放的长度不同吗?



还有如下问题:
HMODULE (__stdcall *MyLoadLibrary)(LPCTSTR); //这应该是定义了一个MyLoadLibrary型的指针变量指向一个函数返回值为一个句柄的函数,其函数参数类型为 LPCTSTR 。  前面的__stdcall启什么作用,

1.参数从右向左压入堆栈
2.函数被调用者修改堆栈
3.函数名(在编译器这个层次)自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸


表示看不懂。。。stdcall的解释

然后 MyLoadLibrary = (HMODULE (__stdcall *)(LPCTSTR)) 这里为一个DWORD类型的地址;  
我想这里应该是一个地址强制转换 但是上面强制转换的类型是句柄型。为什么不直接用(HMODULE *)来转换呢?

最佳答案

查看完整内容

指针的类型除了表明所指向内存的大小外,还指明了如何解释该内存中的数据,比如在32位系统中,int和float都是占据4个字节,那么对于 int a = 1; 这里1在内存中用补码表示,就是000000..0001(共32个2进制位) int* p = &a; printf("%d\n",*p); 这里将p锁指向的内存以int的方式来理解(就是将其视为补码),所以得到1 而 float* p = (float*)&a; printf("%f\n",*p); 这里将p锁指向的内存以float的方式来理解(你只要知道肯 ...
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2013-7-1 22:14:31 | 显示全部楼层
指针的类型除了表明所指向内存的大小外,还指明了如何解释该内存中的数据,比如在32位系统中,int和float都是占据4个字节,那么对于
int a = 1;
这里1在内存中用补码表示,就是000000..0001(共32个2进制位)
int* p = &a;
printf("%d\n",*p);
这里将p锁指向的内存以int的方式来理解(就是将其视为补码),所以得到1

float* p = (float*)&a;
printf("%f\n",*p);
这里将p锁指向的内存以float的方式来理解(你只要知道肯定和int的理解不一样就可以了,实际上是用IEEE754的短浮点数标准来理解的),所以得到的不是1,至于要明白为什么会得到那个数字则需要深刻理解IEEE754的短浮点数标准(这个已经偏离了本主题)

对于函数调用的__stdcall,这个东西在基础的C语言中不会遇到,因为反正你的函数都是自己实现,自己调用的,实现和调用的约定默认情况下都是一样的。但是在使用动态链接库的时候,你调用的函数不是你自己实现的,甚至不是用C语言实现的,而各种语言中对于函数的理解是不一样的(具体参见你自己帖子里的那些话)所以必须统一到底这个函数到底是用那种理解方式来理解,除了__stdcall外还有__cdecl等规则。

最后,
MyLoadLibrary = (HMODULE (__stdcall *)(LPCTSTR)) 这里为一个DWORD类型的地址;  
你既然已经知道了HMODULE (__stdcall *)(LPCTSTR)是一个函数指针的类型,并且MyLoadLibrary就是这个函数指针的类型,现在要把一个值强制转换为这个类型,难道不应该像你帖子中描述的那样写吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2013-7-1 23:47:02 | 显示全部楼层
首先stdcall是一种调用函数约定,是指c的方式,另一种 常见的方式是_cdecl,c++方式
  首先,函数,可以理解为段代码的首地址,函数调用,就是要从当前位置,跳到那段代码去执行,然后,还要能返回到跳转的地方的下一条语句执行。
  这里,有几个问题,
1.就是,跳到那一段代码去执行的时候,要给那一段代码一些信息,怎么提供这些信息呢,那就是函数参数,或者全局变量了,但,这是高级语言里面的东东,要经过转换成汇编语言,到最终可执行的机器码。汇编里面实现传递参数是通过栈来实现的,那么,一个函数有多个参数的情况下,怎么压栈,从右至左,还是从左至右,两者都可以,所以不同的语言,有不同的方式,像C,就是用的前者,也就是你所问的stdcall了,c++用的又是另一种_cdecl
2.函数执行完毕,要返回到跳转位置的下一行代码继续执行,又有一个问题了,我们跳过去执行的那一段代码,事先怎么可能知道跳转前的下一行要执行代码的地址呢,一个程序中会调用不同的函数,这些个函数都要知道他们返回去执行的地址是什么,这时候,肯定是要一种通用的方法了,很简单,就是在参数压栈完后,将返回地址入栈,这样返回地址也通过栈传递给那一段要执行代码了,不过是那个函数,每个函数都知道自己有几个参数的,那么他就可以知道,他要返回的地址在那里了。
3. 前面1,2问题解决了,既然,每一个函数,都要通过栈来获取他需要的参数,返回去执行的代码的地址,他么,也就是在每个函数执行过程中,他自己的栈空间是要保持不变的,或者说,他自己用的那一部分,是不变的,那么,在他调用其他函数的时候参数入栈,返回地址入栈等,改变了这个栈空间,那么,再调用的函数返回的时候,就要恢复到他自己使用的栈状态,那么,这个恢复过程,由谁来负责,是调用函数,还是被调用函数呢,这两都又是都可以的,c和c++的实现方式又不同了。这就是stdcall和_cdecl的区别之一。
4.好吧,前面3点,可以看到stdcall 和 _cdecl 的函数调用方式有这么多的不同,且一个是c的,一个是c++的,我们知道,c 和 c++,在我们的代码中是没有严格区分开来的,即两者可以任意穿插,调用等。
那么,问题来了,如果是我们自己写的c函数,那么,这没有什么,因为,最终他是被识别成c还是c++我们不用去关心。但是,对于,我们调用到的c运行时库中的函数,或者,函数明确定义为c实现的函数,要怎么和c++的函数区别呢。或者说,编译器在编译这些函数的时候,怎么区分是c还是c++的函数,因为,我们知道,c和c++,或者说stdcall和_cdecl两种函数调用约定,实现方式是不同的,因此,为了区分这两种调用约定的函数,编译器在翻译两种函数,用符号表示的时候,加了一些特殊的标记,即下划线等来区分了
{:1_1:},写了一堆废话,希望不要误导你,:lol
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2013-7-1 23:55:03 | 显示全部楼层
     好像偏题了,再补充几句废话,
    关于指针,首先,要明确一点,指针,其实就是一个地址,或者说一个整数值,用来表示内存中用来存放一段数据的内存编号,你完全可以把他当做一个整型值来看待。
    关于强制转换,如果把内存地址看成是房间,那么,不同的类型,可以看成是,卧室,厨房,厕所等,那么都是房间,可以编不同的号,但是如果只给你编号,你怎么知道是卧室,还是厨房,还是厕所呢? 或者说,你怎不能说,厕所是厨房,厨房是卧室吧!
   :lol,又来误导你了,哈哈
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-21 08:06

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表