C/C++ 与函数有关的typedef用法
2015-05-05 22:12
435 查看
今天搞了一天的仓储管理,身心憔悴啊。
晚上师弟过来问linux c编程关于typedef的用法,typedef怎么说呢,仔细想觉得水很深,但是常见的
首先来复习一下基础知识
1. 函数指针
结合反汇编来看一下吧:
对函数指针比较了解,但是对于下面这个another有些郁闷了,
可以看到,在编译器编译过程中
强转是个好习惯,但是人有时候偷懒就不想自己强转,在涉及到指针偏移的时候可能会出错,因为编译器的默认转化可能不是我们想要的结果。一定要注意。
我们来想下一个问题,为什么在typedef的时候,需要带上返回值类型和参数列表。准确的说,这是一个关于函数指针定义的问题。
来看一下普通函数的调用方式:
所有的高级语言都这是一个接口,看看汇编层次:
首先,你需要压入参数吧,就必须定义push的多少,编译器就需要知道参数数目,所以定义的时候要(int,int ,,,,).
接着吧,你还要知道返回的值取的长度,
在我们眼里,函数地址就是一个地址,但是只有一个地址是不能够完成函数调用的,不是说你call 401005 就能完成sum函数。因为函数调用需要上下文条件,所以定义的时候才必须提供参数,和返回值类型。
函数指针变量存放的就只是
关于指针插个题外话:
总结:typedef在看不懂的时候将typedef这个词给删除了,后面应该就是一个变量的普通定义,记住这一点。
晚上师弟过来问linux c编程关于typedef的用法,typedef怎么说呢,仔细想觉得水很深,但是常见的
typedef也就几种类型,现在总结下。为了更好的体验,我用
vc6.0写了一个程序,如下:
#include <stdio.h> typedef int (*func)(int ,int); //变量类型 func,为函数指针类型 typedef int (another)(int,int); //变量类型? another,函数名变量?,比较疑惑 /*int another(int,int); 刚开始搞不懂第二个和函数指针的区别,最后发现把typedef去掉,不就是个类似函数声明的东西嘛。。。 从我现在的阅历来看,找不到`typedef int (another)(int,int);`的用处,因为你后期调用的时候还 不得`another * param`嘛,这不就是函数指针嘛。。 */ int sum(int a,int b) { return a+b; } int main() { int result; func p; another *test; //其实就是func test. // another test ; //不能通过编译,那定义了有毛线作用啊,就为了引用指针为毛不直接 func test呢。 //所以上文我才说这种typedef是毫无意义的,希望有大牛看到这里打脸。 result=sum(1,2); printf ("sum=%d\n",result); p =(func)sum; result=p(1,2); printf ("sum=%d\n",result); p =(func)sum; result=(*p)(1,2); printf ("sum=%d\n",result); p =(func)∑ result=p(1,2); printf ("sum=%d\n",result); p =∑ result=p(1,2); printf ("sum=%d\n",result); p =sum; result=p(1,2); printf ("sum=%d\n",result); *test =sum; result=test(1,2); printf ("sum=%d\n",result); return 0; } output: sum=3 (repeate-7times)
首先来复习一下基础知识
1. 函数指针
int max(int a,int b){return max_number of a or b} //伪代码 int(*p)(int,int); //声明一个函数指针 p =max usage: p(1,2) (*p)(1,2)
结合反汇编来看一下吧:
1: #include <stdio.h> 2: typedef int (*func)(int ,int); 3: typedef int (another)(int,int); 4: //int another(int,int); 5: 6: int sum(int a,int b) 7: { 00401020 push ebp 00401021 mov ebp,esp 00401023 sub esp,40h //default stack space,no local parameter exist. 00401026 push ebx 00401027 push esi 00401028 push edi 00401029 lea edi,[ebp-40h] 0040102C mov ecx,10h 00401031 mov eax,0CCCCCCCCh 00401036 rep stos dword ptr [edi] 8: return a+b; 00401038 mov eax,dword ptr [ebp+8] //a 0040103B add eax,dword ptr [ebp+0Ch] //b 9: } 0040103E pop edi 0040103F pop esi 00401040 pop ebx 00401041 mov esp,ebp 00401043 pop ebp 00401044 ret 11: int main() 12: { 0040D740 push ebp 0040D741 mov ebp,esp 0040D743 sub esp,4Ch 0040D746 push ebx 0040D747 push esi 0040D748 push edi 0040D749 lea edi,[ebp-4Ch] //cH=4bytes*3 0040D74C mov ecx,13h 0040D751 mov eax,0CCCCCCCCh 0040D756 rep stos dword ptr [edi] 13: int result; 14: func p; 15: another *test; 16: result=sum(1,2); 0040D758 push 2 0040D75A push 1 0040D75C call @ILT+0(_sum) (00401005) 0040D761 add esp,8 0040D764 mov dword ptr [ebp-4],eax 17: printf ("sum=%d\n",result); 0040D767 mov eax,dword ptr [ebp-4] 0040D76A push eax 0040D76B push offset string "sum=%d\n" (0042201c) 0040D770 call printf (004010b0) 0040D775 add esp,8 18: 19: p =(func)sum; 0040D778 mov dword ptr [ebp-8],offset @ILT+0(_sum) (00401005) 20: result=p(1,2); 0040D77F mov esi,esp 0040D781 push 2 0040D783 push 1 0040D785 call dword ptr [ebp-8] 0040D788 add esp,8 0040D78B cmp esi,esp 0040D78D call __chkesp (00401130) 0040D792 mov dword ptr [ebp-4],eax 21: printf ("sum=%d\n",result); 0040D795 mov ecx,dword ptr [ebp-4] 0040D798 push ecx 0040D799 push offset string "sum=%d\n" (0042201c) 0040D79E call printf (004010b0) 0040D7A3 add esp,8 22: 23: p =(func)sum; 0040D7A6 mov dword ptr [ebp-8],offset @ILT+0(_sum) (00401005) 24: result=(*p)(1,2); 0040D7AD mov esi,esp 0040D7AF push 2 0040D7B1 push 1 0040D7B3 call dword ptr [ebp-8] //可以看到,p(1,2) =(*p)(1,2),都是call [ebp-8] 0040D7B6 add esp,8 0040D7B9 cmp esi,esp 0040D7BB call __chkesp (00401130) 0040D7C0 mov dword ptr [ebp-4],eax 25: printf ("sum=%d\n",result); 0040D7C3 mov edx,dword ptr [ebp-4] 0040D7C6 push edx 0040D7C7 push offset string "sum=%d\n" (0042201c) 0040D7CC call printf (004010b0) 0040D7D1 add esp,8 26: 27: p =(func)∑ 0040D7D4 mov dword ptr [ebp-8],offset @ILT+0(_sum) (00401005) //可以看到编译过程中sum=&sum 28: result=p(1,2); 0040D7DB mov esi,esp 0040D7DD push 2 0040D7DF push 1 0040D7E1 call dword ptr [ebp-8] 0040D7E4 add esp,8 0040D7E7 cmp esi,esp 0040D7E9 call __chkesp (00401130) 0040D7EE mov dword ptr [ebp-4],eax 29: printf ("sum=%d\n",result); 0040D7F1 mov eax,dword ptr [ebp-4] 0040D7F4 push eax 0040D7F5 push offset string "sum=%d\n" (0042201c) 0040D7FA call printf (004010b0) 0040D7FF add esp,8 30: 31: p =∑ //可以看到,没有对&sum强转,也变成了(func)∑ 0040D802 mov dword ptr [ebp-8],offset @ILT+0(_sum) (00401005) 32: result=p(1,2); 0040D809 mov esi,esp 0040D80B push 2 0040D80D push 1 0040D80F call dword ptr [ebp-8] 0040D812 add esp,8 0040D815 cmp esi,esp 0040D817 call __chkesp (00401130) 0040D81C mov dword ptr [ebp-4],eax 33: printf ("sum=%d\n",result); 0040D81F mov ecx,dword ptr [ebp-4] 0040D822 push ecx 0040D823 push offset string "sum=%d\n" (0042201c) 0040D828 call printf (004010b0) 0040D82D add esp,8 34: 35: p =sum; 0040D830 mov dword ptr [ebp-8],offset @ILT+0(_sum) (00401005) 36: result=p(1,2); 0040D837 mov esi,esp 0040D839 push 2 0040D83B push 1 0040D83D call dword ptr [ebp-8] 0040D840 add esp,8 0040D843 cmp esi,esp 0040D845 call __chkesp (00401130) 0040D84A mov dword ptr [ebp-4],eax 37: printf ("sum=%d\n",result); 0040D84D mov edx,dword ptr [ebp-4] 0040D850 push edx 0040D851 push offset string "sum=%d\n" (0042201c) 0040D856 call printf (004010b0) 0040D85B add esp,8 38: 39: *test =sum; //test=sum is wrong 0040D85E mov dword ptr [ebp-0Ch],offset @ILT+0(_sum) (00401005) 40: result=test(1,2); //此处(*test)(1,2) 也一致,可通过。 0040D865 mov esi,esp 0040D867 push 2 0040D869 push 1 0040D86B call dword ptr [ebp-0Ch] 0040D86E add esp,8 0040D871 cmp esi,esp 0040D873 call __chkesp (00401130) 0040D878 mov dword ptr [ebp-4],eax 41: printf ("sum=%d\n",result); 0040D87B mov eax,dword ptr [ebp-4] 0040D87E push eax 0040D87F push offset string "sum=%d\n" (0042201c) 0040D884 call printf (004010b0) 0040D889 add esp,8 42: return 0; 0040D88C xor eax,eax 43: } 0040D88E pop edi 0040D88F pop esi 0040D890 pop ebx 0040D891 add esp,4Ch 0040D894 cmp ebp,esp 0040D896 call __chkesp (00401130) 0040D89B mov esp,ebp 0040D89D pop ebp 0040D89E ret
对函数指针比较了解,但是对于下面这个another有些郁闷了,
another到底能不能算一个变量类型,这不是一个函数名嘛,也即常量啊,有没有朋友知道怎么去解决这个问题。
typedef int (another)(int,int); //变量类型? another,函数名也能算变量类型?比较疑惑 //int another(int,int);
可以看到,在编译器编译过程中
&sum ,sum都是同一个数。我感觉这个严重伤害老百姓的感情,该怎么定义就怎么定义,否则很容易让人搞混。
强转是个好习惯,但是人有时候偷懒就不想自己强转,在涉及到指针偏移的时候可能会出错,因为编译器的默认转化可能不是我们想要的结果。一定要注意。
我们来想下一个问题,为什么在typedef的时候,需要带上返回值类型和参数列表。准确的说,这是一个关于函数指针定义的问题。
来看一下普通函数的调用方式:
int result = sum(1,2); 0040D758 push 2 0040D75A push 1 0040D75C call @ILT+0(_sum) (00401005) 0040D761 add esp,8 0040D764 mov dword ptr [ebp-4],eax
所有的高级语言都这是一个接口,看看汇编层次:
首先,你需要压入参数吧,就必须定义push的多少,编译器就需要知道参数数目,所以定义的时候要(int,int ,,,,).
接着吧,你还要知道返回的值取的长度,
int sum(int,int)就代表了要
dword ptr 还是 word ptr,或者 byte ptr.
在我们眼里,函数地址就是一个地址,但是只有一个地址是不能够完成函数调用的,不是说你call 401005 就能完成sum函数。因为函数调用需要上下文条件,所以定义的时候才必须提供参数,和返回值类型。
函数指针变量存放的就只是
sum的地址,但靠此地址不能完成调用,sum函数还没有完成,所以一个函数指针必须要提供返回值类型和参数类型,这时候编译器才能将完成对整个函数的汇编级编译。
关于指针插个题外话:
*在前表示取指向的值,*在后表示声明类型,常用于强制转化。比如*p 表示取p指向的值,p* 表示p类型的指针。关于这个知识点,常常和char* a, *a 做类比,就知道了。
总结:typedef在看不懂的时候将typedef这个词给删除了,后面应该就是一个变量的普通定义,记住这一点。
相关文章推荐
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- typedef函数指针的用法(C++)(转载)
- 转:typedef函数指针的用法(C++)
- C/C++之typedef函数指针用法
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- [C++基础]typedef 函数指针的用法
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- typedef函数指针的用法(C++)
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- typedef函数指针的用法(C++)
- typedef函数指针的用法(C++)
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- 一篇非常好的介绍c、c++中有关时间函数的用法
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- (转)关于C++中函数指针的使用(包含对typedef用法的讨论)
- typedef函数指针的用法(C++)