首页
社区
课程
招聘
函数指针与typedef
发表于: 2010-2-14 02:02 9235

函数指针与typedef

2010-2-14 02:02
9235
为了快速找到答案我在百度也发了,有百度号的大神可以进去指点我下 我追加分的!
http://zhidao.baidu.com/question/137690016.html?fr=middle_ask

#include <windows.h>
#include <stdio.h>
void (*ProcAdd)(LPTSTR);
int main()
{       
        HINSTANCE LibHandle;
                  LibHandle = LoadLibrary("user32");
                printf("msvcrt LibHandle = //x%x\n", LibHandle);
                ProcAdd=(void (*)(LPTSTR))GetProcAddress(LibHandle,"MessageBoxA");        //这里不懂
                printf("system = //x%x\n", ProcAdd);
                return 0;
}
等价于
#include <windows.h>
#include <stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main()
{       
        HINSTANCE LibHandle;
        MYPROC ProcAdd;
                  LibHandle = LoadLibrary("user32");
                printf("msvcrt LibHandle = //x%x\n", LibHandle);
                ProcAdd=(MYPROC)GetProcAddress(LibHandle,"MessageBoxA");        //这里不懂
                printf("system = //x%x\n", ProcAdd);
                return 0;
}
函数指针指向某函数必须要 参数类型相同,参数数目相同.
这里我感觉不解为什么这样是对的?
我也猜想过
是不是
GetProcAddress函数的返回值(是一个指针)强制转换成函数指针类型?然后给ProcAdd?但是函数指针指向某函数必须要 参数类型相同,参数数目相同.难道是我理解错了.(绝对这样猜想不靠谱)
看雪的大神 指点下,困扰我1下午了连吃年夜饭都在想这个
已经标出来了不懂地方

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
免费 0
支持
分享
最新回复 (33)
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
睡前人工置顶
2010-2-14 02:12
0
雪    币: 2362
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
管它什么指针 还不是个DWORD
所以这样也可以
2010-2-14 02:13
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
#include <windows.h>
#include <stdio.h>
int main()
{  
  HINSTANCE LibHandle;
  FARPROC farproc;
      LibHandle = LoadLibrary("user32");
    printf("msvcrt LibHandle = //x%x\n", LibHandle);
    farproc=GetProcAddress(LibHandle,"MessageBoxA");  
   printf("system = //x%x\n", farproc);
    return 0;
}
这样也可以通过成功获取函数地址,但是我就是不懂 1楼那个 函数指针 到底是怎么回事
2010-2-14 02:34
0
雪    币: 399
活跃值: (38)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
5
编译正确=正确稳定运行?
2010-2-14 12:44
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
编译当然正确,都是DWORD嘛,呵呵,ls正解,编译正确甚至在你的机器上运行正确并不能代表程序就是正确的。

至于函数指针,很好理解,函数的名字指代的就是函数的首地址(就像数组的名字一样),调用一个函数可以通过函数的名字来调用func(1,2),那自然也可以用一个指向函数的指针的来调用这个函数(*pFunc)(1,2),这两者是一样的,就像下面:

#include<iostream>
using namespace std;

typedef void(*pFunc)(int);

void func(int a)
{
        cout << a << endl;
}

int main()
{
        func(7);           //这总没问题吧
        pFunc pf = func;
        (*pf)(11);         //函数指针

        cout << func << endl;
        cout << pf << endl;           //这两者显然是一样的
   
        return 0;
}
2010-2-14 13:05
0
雪    币: 450
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
首先,你的那段代码是有错误的...
函数指针本质上也是指针,内容为函数的首地址。
GetProcAddress 的返回值类型为 FARPROC
因为 FARPROC 和 MYPROC 不兼容,所以你在赋值时使用了强制转换...
声明只是在编译阶段起到检查作用,所以不会阻止你进行强制类型转换,但当你使用时:
(*ProcAdd)(...);
你便会发现只有输入单个 LPTSTR 类型时才能编译通过,但运行时是肯定会崩溃的~
因为实际上函数接受4个参数,这就说明使用函数指针的危险性,关键是要理解函数指针的正确声明。
2010-2-14 13:13
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
依然没得到...
3L 不管那一段代码编译后,获取的地址都是一样的 正确的.
我就是想问那个函数指针到底是怎么样事
2010-2-14 13:30
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
6楼
你那个例子
既然pf指向func函数的首地址
下面一句何必这样写了?(*pf)(11);  改成pf(11); 直接调用pf指向的地址函数 不是更简洁?
2010-2-14 13:56
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
你调用MessageBox的时候可以这样写:
push
push
push
push
call MessageBox
这就好比高级语言里写MessageBox(NULL,offset szText,offset szCaption,MB_OK),这是我们常用的调用方式(C里可没有offset,哈哈)。

你也可以通过fp = (FARPROC)GetProcAddress(LoadLibrary("user32.dll"),"MessageBoxA")来获得MessageBoxA的地址,然后这样调用:
push
push
push
push
call fp
这就好比是(*fp)(NULL,offset szText,szCaption,MB_OK),在高级语言的角度来看,两者是不同的,但是在汇编的角度来看,两者其实是一回事,因为函数的名字本身就存储着函数的地址,函数的名字本身就是一个函数指针,我们调用函数的时候用谁都一样,都是用的函数的地址。只是函数名字存储函数地址这个事实被编译器给隐藏了,我们平时也不在意。

返回值类型 函数名字(参数)
返回值类型 函数地址(参数)

两者是一回事~
2010-2-14 14:01
0
雪    币: 450
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
函数指针在x86平台长度是4字节,其本质上还是指针,指向的内容为函数的首地址。
申明一般如下:
返回值类型 (*变量名)(形参列表);
形参列表是可选的。
例如:
void (*ProcAdd)(LPTSTR);
声明了名为ProcAdd的指针,他指向的函数接受1个LPTSTR类型参数,无返回值。
2010-2-14 14:05
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
11楼
我说的不是 函数指针声明;
我说
ProcAdd=(MYPROC)GetProcAddress(LibHandle,"MessageBoxA");  //这里不懂
ProcAdd=(void (*)(LPTSTR))GetProcAddress(LibHandle,"MessageBoxA");  //这里不懂
为什么这样可以强制转换
2010-2-14 14:11
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
额,这我倒没想过,呵呵,一直用(*pf)(11)写习惯了……不知有区别没,貌似没有,呵呵。

建议你直接从汇编的角度的理解吧,高级语言里的函数调用不过就是

push eip
jmp 函数地址

这个函数地址你爱怎么获得怎么获得,用函数名字也好,用你自己弄的函数指针也罢,你直接写出来这个地址都行,也就是说只要地址是同样的,你爱咋写咋写
2010-2-14 14:14
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
这是C语言的规定……这样写就是进行强制类型转换的……没有为什么……
2010-2-14 14:16
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
晕,我知道你为什么不懂了,是因为形式的原因……
ProcAdd=(void (*)(LPTSTR))GetProcAddress(LibHandle,"MessageBoxA");
你不知道为什么用(void (*)(LPTSTR))来进行强制类型转换是不是?

因为你写的是 typedef void(*MYPROC)(LPTSTR) ,这样写那么就意味着你定义了一个新的数据类型,叫做MYPROC。去掉typedef,去掉你定义的类型名MYPROC,就剩下void(*)(LPTSTR)了,所以你新定义的这个数据类型就是void(*)(LPTSTR)类型的,所以强制类型转换时要写成(void(*)(LPTSTR))这种奇怪的样子……

而你写了typedef ……之后,(void (*)(LPTSTR))也就是MYPROC了,俩是一样的,所以你也可以用(MYPROC)来进行强制类型转换。
2010-2-14 14:23
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
14楼
你的意思是?
GetProcAddress把它强制转换成MYPROC?  GetProcAddress他是有返回值的,MYPROC定义是他是void  这样也可以强制?
ProcAdd=(MYPROC)GetProcAddress(LibHandle,"MessageBoxA"); //这里 既然你说强制转换成MYPROC ,那应该没反正值啊 为什么ProcAdd 还可以接收返回值?
2010-2-14 14:23
0
雪    币: 450
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
C语言同时给了程序员最大的编程自由度和严格的类型检查机制。
FARPROC定义如下:
typedef int (__stdcall *FARPROC)();
明显与MYPROC定义不兼容,显示的强制转换是因为编译器希望确认这的确是你希望要做的。
正因为如此,显示的强制类型转换是不安全的。
2010-2-14 14:25
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
15楼
typedef 简化代码我知道啊!
我在一楼写了2个版本的.
回答我16
楼问题就行了
2010-2-14 14:30
0
雪    币: 450
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
终于懂你的意思了,强制转换的是返回值,也就是把FARPROC转成MYPROC啊......
注意优先级的问题
2010-2-14 14:30
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
不是void,看我在15L的解释,就好像 typedef bool BOOLEAN;一样,以后需要用bool的地方也就可以用BOOLEAN来代替了。

同理  typedef void(*MYPROC)(LPTSTR),那么以后需要用 void(*)(LPTSTR)的地方也就可以用MYPROC代替了。

PS:为了这个分我可真是尽心竭力了……还差3分就够钱买个邀请码了……
2010-2-14 14:31
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21

你15楼那个回答我 知道啊!
程序原版是 typedef 定义了函数指针类型
我在原版程序改成了ProcAdd=(void (*)(LPTSTR))GetProcAddress(LibHandle,"MessageBoxA");  这种奇怪的格式.
2010-2-14 14:38
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22

我想问的 GetProcAddress(有返回值)强制转换成 无返回值的 函数指针 这样可以?
还有就是 就算转换成功 他应该没返回值啊 怎么可以用ProcAdd接受返回值
就是这样
2010-2-14 14:42
0
雪    币: 450
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
[QUOTE=wonderu;762139]终于懂你的意思了,强制转换的是返回值,也就是把FARPROC转成MYPROC啊......
注意优先级的问题[/QUOTE]
没有强制转换GetProcAddress啊
是返回的FARPROC类型的指针变量......
2010-2-14 14:45
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
不知你到底想知道什么……囧……

如果不是专门问函数指针问题的话,建议你直接按M$的写法写就是了:

FARPROC WINAPI GetProcAddress(
            __in HMODULE hModule,
            __in LPCSTR lpProcName);

直接强制转换成FARPROC,也不用管其它的了……
或者
FARPROC uAddr;
(FARPROC &) uAddr = GetProcAddress(LoadLibrary("user32.dll"),"MessageBoxA");

自己看着写呗,只要没犯原则性错误就是了……
2010-2-14 14:47
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
19楼wonderu
终于看到了!我问的就是这个返回值
你说下吧!

ProcAdd=(void (*)(LPTSTR))GetProcAddress(LibHandle,"MessageBoxA");  这个到底是怎么执行的,说明白点 我1楼倒数第二行开始也假设过!
2010-2-14 14:50
0
游客
登录 | 注册 方可回帖
返回
//