一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
楼主: kenson
收起左侧

C 中复杂的函数声明

[复制链接]
发表于 2015-6-17 14:02 | 显示全部楼层
看到这类代码就想打人
 楼主| 发表于 2015-6-18 12:44 | 显示全部楼层
xzp21st 发表于 2015-6-17 14:02( _) \3 R2 `4 ^7 n8 c
看到这类代码就想打人
% a, e# e1 V, g( n9 F3 G4 A6 c* n; g
你想往高层去走如运行RTOS系统这类的你也要对这方面要懂得一点。
 楼主| 发表于 2015-6-18 12:51 | 显示全部楼层
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。, W7 E! p6 G$ j5 D9 p2 S  Q4 e9 ]
网址:http://www.state-machine.com/
8 W3 G# t! M/ f, _8 d极力推荐!!!
发表于 2015-6-18 14:11 | 显示全部楼层
kenson 发表于 2015-6-18 12:51" r$ ~" M; s% W- `5 [
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。
/ q8 ~& ?8 y* y' m网址:http://www.s ...
3 [; T0 [# {" ]% {  p
这不是量子状态机嘛1 ~5 Y$ h7 T2 W
 楼主| 发表于 2015-6-18 14:50 | 显示全部楼层
xzp21st 发表于 2015-6-18 14:11
, l* n( o$ Y/ D- `0 L$ v4 D这不是量子状态机嘛
! R% k8 W0 q4 U0 l4 G
是的!怎样对这个熟悉吗?. t6 b! i" {! h# ?3 k; `7 p+ a
 楼主| 发表于 2015-6-20 07:57 | 显示全部楼层
指向函数指针的指针7 @4 X3 f) f* r0 c
typedef int *(*pfun_t)(int a, int b)
' b( G# q' b5 s) [, apfun_t *ppfun_t = NULL;
 楼主| 发表于 2015-6-21 13:45 | 显示全部楼层
1.函数指针的定义

4 d' k1 ]: q" J5 B; g  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
  
1
  
2
  
3
  
A) char * (*fun1)(char * p1,char * p2);
  
B) char * *fun2(char * p1,char * p2);
  
C) char * fun3(char * p1,char * p2);
  
看看上面三个表达式分别是什么意思?
5 t! H9 [/ \8 d' j5 r6 u
C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。. G0 S7 [" _# r9 j7 i9 y) A- z
B) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。
& I# n; d) x# u4 }2 @A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
  
1
  
int (*)[10]  p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
  
1
  
char *  (*)(char * p1,char * p2) fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。^_^。
2.函数指针使用的例子
7 V$ b9 M' r. M5 T
  上面我们定义了一个函数指针,但如何来使用它呢?先看如下例子:
  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
#include <stdio.h>
  
#include <string.h>
  
  
char *  fun(char * p1,char * p2)
  
{
  
  int i = 0;
  
  i = strcmp(p1,p2);
  
  
  if (0 == i)
  
  {
  
    return p1;
  
  }
  
  else
  
  {
  
    return p2;
  
  }
  
}
  
  
int main()
  
{
  
  char * (*pf)(char * p1,char * p2);
  
  pf = &fun;
  
  (*pf)  ("aa","bb");
  
  return 0;
  
}
  我们使用指针的时候,需要通过钥匙(“*”)来取其指向的内存里面的值,函数指针使用也如此。通过用(*pf)取出存在这个地址上的函数,然后调用它。
  这里需要注意到是,在Visual C++6.0里,给函数指针赋值时,可以用&fun或直接用函数名fun。这是因为函数名被编译之后其实就是一个地址,所以这里两种用法没有本质的差别。这个例子很简单,就不再详细讨论了。
3.*(int*)&p----这是什么?

2 n/ J3 n2 i. B& R8 o/ `% y  也许上面的例子过于简单,我们看看下面的例子:
  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
void Function()
  
{
  
  printf("Call  Function!\n");
  
}<br>
  
int main()
  
{
  
  void (*p)();
  
  *(int*)&p=(int)Function;
  
  (*p)();
  
  return 0;
  
} 

7 Z! x) ?. J3 r% U. z6 I5 f这是在干什么?*(int*)&p=(int)Function;表示什么意思?
4 e& m! l4 o& u# c别急,先看这行代码:
  
1
  
void (*p)();
这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。
0 g+ I( \3 {2 D& p7 M&p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。
; L5 Z( _" c% c8 M3 a/ v% c(int*)&p表示将地址强制转换成指向int类型数据的指针。
2 z# s/ |8 {0 `' E# X(int)Function表示将函数的入口地址强制转换成int类型的数据。: }  k4 y) |& t4 ^
分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。

) n0 s# l% e) y: N' E% i/ N/ T# V) `那么(*p) ();就是表示对函数的调用。
' t1 G( r& O- y: x: S" S
讲解到这里,相信你已经明白了。其实函数指针与普通指针没什么差别,只是指向的内容不同而已。1 F6 m, ]! _( [6 S" b
使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或者归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。
4.(*(void(*)())0)()------这是什么?

, Z- R. X+ X+ k) l2 L+ ?2 X  是不是感觉上面的例子太简单,不够刺激?好,那就来点刺激的,看下面这个例子:
  
1
  
(*(void(*) ())0)();
这是《C Traps and Pitfalls》这本经典的书中的一个例子。没有发狂吧?下面我们就来分析分析:
  
1
  
2
  
3
  
4
  
第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。
  
第二步:(void(*) ())0,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。
  
第三步:(*(void(*) ())0),这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。
  
第四步:(*(void(*) ())0)(),这是函数调用。

: {2 X2 x4 T; k8 ^+ M好像还是很简单是吧,上面的例子再改写改写:
  
1
  
(*(char**(*) (char **,char **))0) ( char **,char **);
  d3 V, \. F$ r: N
如果没有上面的分析,肯怕不容易把这个表达式看明白吧。不过现在应该是很简单的一件事了。读者以为呢?
5.函数指针数组
  现在我们清楚表达式
  
1
  
char *  (*pf)(char * p);
定义的是一个函数指针pf。既然pf是一个指针,那就可以储存在一个数组里。把上式修改一下:
  
1
  
char *  (*pf[3])(char * p);
这是定义一个函数指针数组。
  它是一个数组,数组名为pf,数组内存储了3个指向函数的指针。这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函数。
  这念起来似乎有点拗口。不过不要紧,关键是你明白这是一个指针数组,是数组。函数指针数组怎么使用呢?这里也给出一个非常简单的例子,只要真正掌握了使用方法,再复杂的问题都可以应对。
如下:
  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
#include <stdio.h>
  
#include <string.h>
  
<br>char * fun1(char * p)
  
{
  
  printf("%s\n",p);
  
  return p;
  
}
  
  
char *  fun2(char * p)
  
{
  
  printf("%s\n",p);
  
  return p;
  
}
  
char *  fun3(char * p)
  
{
  
  printf("%s\n",p);
  
  return p;
  
}
  
<br>int main()
  
{
  
  char * (*pf[3])(char * p);
  
  pf[0] = fun1; //可以直接用函数名
  
  pf[1] = &fun2; //可以用函数名加上取地址符
  
  pf[2] = &fun3;<br>
  
  pf[0]("fun1");
  
  pf[0]("fun2");
  
  pf[0]("fun3");
  
  return 0;
  
} 
6.函数指针数组的指针
  ?$ j4 E& E9 e8 h: d. T
  看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。
' u3 R3 n% c6 v$ N8 i$ f2 S( B其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。

) K1 w: x. S/ T. v6 i- t下面就定义一个简单的函数指针数组指针:
  
1
  
char *  (*(*pf)[3])(char * p);

" w( w' [3 X& F注意,这里的pf和上一节的pf就完全是两码事了。上一节的pf并非指针,而是一个数组名;这里的pf确实是实实在在的指针。这个指针指向一个包含了3个元素的数组;这个数字里面存的是指向函数的指针;这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函数。
  这比上一节的函数指针数组更拗口。其实你不用管这么多,明白这是一个指针就ok了。其用法与前面讲的数组指针没有差别。下面列一个简单的例子:
  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
  
36
  
#include <stdio.h>
  
#include <string.h>
  
  
char *  fun1(char * p)
  
{
  
    printf("%s\n",p);
  
    return p;
  
}
  
  
char *  fun2(char * p)
  
{
  
    printf("%s\n",p);
  
    return p;
  
}
  
  
char *  fun3(char * p)
  
{
  
    printf("%s\n",p);
  
    return p;
  
}
  
  
int main()
  
{
  
    char * (*a[3])(char * p);
  
    char * (*(*pf)[3])(char * p);
  
    pf =  &a;
  
  
    a[0]  = fun1;
  
    a[1]  = &fun2;
  
    a[2]  = &fun3;
  
  
    pf[0][0]("fun1");
  
    pf[0][1]("fun2");
  
    pf[0][2]("fun3");
  
    return 0;
  
}
  
 楼主| 发表于 2015-6-21 14:22 | 显示全部楼层
大家可以用仿真软件仿真一下这个程序' `0 j+ ?9 J0 c9 ~( q7 c

! R" I% q0 [+ b+ N- I: d# e! Y0 Z
#include <REG52.H>                /* special function register declarations   */
! j0 |7 L$ K- v/ u3 e' l9 k# L6 @9 H#include <stdlib.h>                                  /* for the intended 8051 derivative         */6 R; W: c! C- ~$ o
#include <string.h>
& Z2 c! S/ I, l  V8 d#include <stdio.h>                /* prototype declarations for I/O functions */' l# R0 y- Z2 ]7 D+ i3 U( A

/ ?# v! c0 b# @) G0 ]& J" D
8 `) p( ?  O9 A4 H, A. C  u/ v#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */
0 _8 q5 ~  z- Q7 L8 Bchar code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */
( E& d9 Z4 F6 R#endif                                   /* Stop Exection with Serial Intr.   */
  \, ?( J5 k2 ^- a                                         /* is enabled                        */
8 o( w1 X9 Z  Y0 o0 r2 [+ |- c- T# m
$ _& n7 ~: r0 _5 w7 M" Achar * fun1(char * p)
2 q: C, |  v4 b# Y{$ }7 D  X/ c# ^8 g  N- }
printf("%s\n",p);& h3 e  `# f0 q' W4 |% y/ I
return p;
" S1 A. X( K% G' Z}8 r, u6 g9 \* {, {* o1 {
& F* C; K4 X: p( z/ U
char * fun2(char * p)
8 i2 Y* `- W. A1 z{; M- R4 L: l. ]% h! _6 r1 F( c
printf("%s\n",p);
6 R1 j3 w+ a& K0 D9 F9 ?return p;
6 S) w1 H; y" k! a2 n: q  D}! \' Y# w+ T$ \) x% C
7 ~# g: g# G0 w
char * fun3(char * p)
0 s* C3 d% F+ P2 `{7 D9 v3 {# Y, N5 X3 ~! c; |
printf("%s\n",p);
* R# \( r9 W0 X: i; Ureturn p;
; A! x! V+ F9 I# g0 L7 V, b; i}
7 ?* Q) j% n$ b/ D" ?; z6 ]: x- g) k" T) u+ z

7 c& F6 {0 O9 d; t
4 \3 a1 p% E6 v, ~. d/ _  }/ t; O# y3 r$ c1 G; X9 Y, ~
! H# m! x) @- }, m, i5 ~/ A
void main (void) {3 E8 l8 C6 m( M- v$ H6 b
3 Z0 h7 p5 [- m1 \* }
char * (*pf[3])(char * p);) [* N; r0 s0 L3 m$ ]
' _+ G( n5 X% \4 h! U( J" N1 }# @
, r" T$ |! Q. y6 Q. R
#ifndef MONITOR51
9 `& n0 n' s. {    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */
3 A: G+ v+ C3 _" V+ I& u; O! [    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */# U% P! J; E! P% n4 I7 |
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */" [; n7 E' |% M  |
    TR1   = 1;                  /* TR1:  timer 1 run                          */
8 u  }5 {/ O8 y    TI    = 1;                  /* TI:   set TI to send first char of UART    */
9 y2 |; N/ Y0 N, i2 m, g7 Y#endif
( U( k! v/ M& j2 F4 l
  ?1 \9 b5 G# E5 v& r! W1 T' i8 L. T  @+ R9 Y
pf[0] = fun1; //可以直接用函数名
6 c, p" W" j3 Rpf[1] = &fun2; //可以用函数名加上取地址符
* @! c0 `: p( z! s& s1 Tpf[2] = &fun3;
! s4 C/ w$ G+ bpf[0]("fun1");2 D2 U9 \3 ~; h2 w8 z. h
pf[0]("fun2");. e4 Z3 T; Y' a
pf[0]("fun3");& ^- W) Z$ Q, n$ s. N% f: ?
while(1);
8 Z6 p) r- A& F6 E# I; m( P) O/ S) f# _4 B: _3 ~
}
# `7 ^( L5 [4 ^* e" |+ M' R3 L
0 i/ M" U8 w' y9 a# {" v6 O: b3 @; {" m( ~" Q7 S
仿真结果:
, s# P0 }9 u' Q& i# N/ tfun1
7 M; R$ m3 @0 x; t' rfun2" M0 V" C: T7 k% Q
fun3
2 R2 Z8 b0 k1 B1 E) r
( z; O1 r0 M+ z' a$ t  a; J
 楼主| 发表于 2015-6-21 16:05 | 显示全部楼层
本帖最后由 kenson 于 2015-6-21 16:12 编辑 ) V  E% M$ S" c5 d5 b! [
& A! f5 L! `4 {$ |  g
void main (void) {$ G, H* p0 ^# u/ i. _5 P
    char * (*a[3])(char * p);
0 W" W0 |. D! F0 V* @    char * (*(*pf)[3])(char * p);
& q' G2 p( s6 T    pf = a;& \. I4 o3 y+ Q% L: K' G
) K7 J3 X: `$ ]) n, Q
3 Z4 ?' ^1 k$ z7 v' y
#ifndef MONITOR51. ?" |, E/ g! \7 Y" X- ~; a
    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */
, }) M3 t- T; `0 @    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
6 r( {  i! v5 F    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
9 W5 U- W& d- j    TR1   = 1;                  /* TR1:  timer 1 run                          */( j4 C. g& E1 O. g% L1 W4 a
    TI    = 1;                  /* TI:   set TI to send first char of UART    */
5 S) p! _2 q7 l5 Q3 ~#endif
3 _. G+ R; T$ ?  M* C( u  b6 o
( @" l! _) a8 c' s7 G4 N0 K( C. X
  I* Z4 B' F5 s5 c6 O
; P8 ^8 x! }( ]- [' g    a[0] = fun1;
0 p: N! s( O3 l9 M, b2 Q2 S    a[1] = &fun2;# J6 W" a2 m' H* s0 _6 A
    a[2] = &fun3;. A( @5 ]  B7 \* x
% s- Z9 g1 q% y8 X
    pf[0][0]("fun1");
5 f, c& y# V2 M5 J    pf[0][1]("fun2");7 M; W& v" O; z  g. N
    pf[0][2]("fun3");
# C7 B+ w# B* {$ h+ e& q9 X7 m" h
( _5 F8 o. V4 P! Rwhile(1);! b8 Z( S4 T6 a

0 B: c( |! ?4 j6 K; A; Q' q! v}
* T  B8 J0 f& Y" k2 [( J( B' p+ \5 E* t$ k3 x7 D: M+ y1 j
/ Q  a+ s" N1 F( U
发表于 2015-7-26 17:09 | 显示全部楼层
学习下,谢谢楼主。

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-5-18 04:40 , Processed in 0.057302 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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