一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
楼主: kenson

C 中复杂的函数声明

[复制链接]
发表于 2015-6-17 14:02 | 显示全部楼层
看到这类代码就想打人
回复

使用道具 举报

 楼主| 发表于 2015-6-18 12:44 | 显示全部楼层
xzp21st 发表于 2015-6-17 14:02
; O5 t# T/ e9 ^7 f5 }看到这类代码就想打人
, |/ @1 D0 l: R) H( \
你想往高层去走如运行RTOS系统这类的你也要对这方面要懂得一点。
回复

使用道具 举报

 楼主| 发表于 2015-6-18 12:51 | 显示全部楼层
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。
* h+ `/ v) f& M4 f网址:http://www.state-machine.com/
& G  }  M7 R( {# D5 e极力推荐!!!
回复

使用道具 举报

发表于 2015-6-18 14:11 | 显示全部楼层
kenson 发表于 2015-6-18 12:51% ~' [/ q) B# J* {( Z3 x& \/ u: R
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。; w. j5 c% |" i! v* E# M3 I
网址:http://www.s ...
- q7 ?( v/ z$ K! H, ^# @9 p" x
这不是量子状态机嘛
( O% P0 I. u  W* C2 }: N' T- W) q: K
回复

使用道具 举报

 楼主| 发表于 2015-6-18 14:50 | 显示全部楼层
xzp21st 发表于 2015-6-18 14:11
. g; g1 h1 q. d4 P# X. g0 j- ?这不是量子状态机嘛
$ ]$ t# D8 z  w
是的!怎样对这个熟悉吗?
8 w% B2 a" W. b1 ]& R& q! Q
回复

使用道具 举报

 楼主| 发表于 2015-6-20 07:57 | 显示全部楼层
指向函数指针的指针1 b; t: _- U/ a: S# N+ ^8 ^
typedef int *(*pfun_t)(int a, int b)0 h, K5 j- d$ Y+ \) J5 Q3 T; C
pfun_t *ppfun_t = NULL;
回复

使用道具 举报

 楼主| 发表于 2015-6-21 13:45 | 显示全部楼层
1.函数指针的定义
8 h& A! |3 V  k$ {
  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
  
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 p; p8 O* c  P: O5 d8 g: y. ?C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。7 O" L) L/ q5 M6 L7 o
B) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。
. \+ R' }# k6 i, F9 `A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
  
1
  
int (*)[10]  p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
  
1
  
char *  (*)(char * p1,char * p2) fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。^_^。
2.函数指针使用的例子

, ?7 x- h  c; w' y0 O  `$ k  上面我们定义了一个函数指针,但如何来使用它呢?先看如下例子:
  
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----这是什么?
6 ]4 n& L2 l5 }/ i0 t9 ^
  也许上面的例子过于简单,我们看看下面的例子:
  
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;
  
} 
2 J7 x9 S# F8 Y5 s
这是在干什么?*(int*)&p=(int)Function;表示什么意思?
7 f. h. X' J  f- `1 I别急,先看这行代码:
  
1
  
void (*p)();
这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。1 _/ _. M# l& S8 ~
&p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。
) m% _1 Y6 E0 o8 f(int*)&p表示将地址强制转换成指向int类型数据的指针。* I; V; h2 D5 ~2 i" `3 t) d2 K
(int)Function表示将函数的入口地址强制转换成int类型的数据。
; ?7 D* a5 L4 _, ]分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。
: T( Q4 U% [9 g8 [4 d& S- T" l
那么(*p) ();就是表示对函数的调用。

& {3 y* B$ M( e0 `. h讲解到这里,相信你已经明白了。其实函数指针与普通指针没什么差别,只是指向的内容不同而已。
* i5 L( O- E1 S& h9 u, k; H使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或者归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。
4.(*(void(*)())0)()------这是什么?
/ @0 ~0 ~6 O* S, J6 g: w
  是不是感觉上面的例子太简单,不够刺激?好,那就来点刺激的,看下面这个例子:
  
1
  
(*(void(*) ())0)();
这是《C Traps and Pitfalls》这本经典的书中的一个例子。没有发狂吧?下面我们就来分析分析:
  
1
  
2
  
3
  
4
  
第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。
  
第二步:(void(*) ())0,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。
  
第三步:(*(void(*) ())0),这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。
  
第四步:(*(void(*) ())0)(),这是函数调用。

( Z1 u6 v# [  k好像还是很简单是吧,上面的例子再改写改写:
  
1
  
(*(char**(*) (char **,char **))0) ( char **,char **);
/ S  C/ a. ~7 y
如果没有上面的分析,肯怕不容易把这个表达式看明白吧。不过现在应该是很简单的一件事了。读者以为呢?
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.函数指针数组的指针

& Q9 @5 m3 `# G2 D' W  看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。2 F! @& }3 o+ i$ \( t2 G% V) K
其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。

- a0 L- q+ O+ `1 D2 w2 h, L  M下面就定义一个简单的函数指针数组指针:
  
1
  
char *  (*(*pf)[3])(char * p);
' e0 Q/ k2 D* m, E
注意,这里的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 | 显示全部楼层
大家可以用仿真软件仿真一下这个程序" P; W& v/ S( j+ {" g

0 Y+ }" R. p6 f0 a6 L7 F4 E; e1 ^! u! X/ O! t5 _6 G4 w
#include <REG52.H>                /* special function register declarations   */
  l- d4 w% o/ @6 c9 i#include <stdlib.h>                                  /* for the intended 8051 derivative         */) _$ w; k6 B% N& g, g2 u; Q
#include <string.h>
6 [6 q' c$ T" I/ E+ T4 j#include <stdio.h>                /* prototype declarations for I/O functions */' p% J" U1 I, G* g, q& U- `

6 N. W# y" `  U1 h) d2 D
1 @8 k1 ~& H0 Q' B( |$ f& X#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */
$ V, g. M" n" @8 rchar code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */( U1 m1 u4 ?& q5 S
#endif                                   /* Stop Exection with Serial Intr.   */: p+ ?6 x; c& D0 v1 a+ g, r
                                         /* is enabled                        */2 ]) z# U: ?! o3 S+ c
7 e  N4 s& Y+ b& t8 ?; ]/ h
char * fun1(char * p)
8 Y% H' c. P) q5 J; p0 {{0 P# Z+ f' s% [9 X
printf("%s\n",p);
" k1 F. B; h/ i) g! preturn p;: K8 b9 K- m0 V# L
}
7 B( G$ K+ X4 f; b% U1 j
8 e4 ^$ j* c- V: ^" I9 tchar * fun2(char * p)
& V! e- p3 }, I6 I8 q" y0 X& _5 q{
& f) G" V( w1 z1 cprintf("%s\n",p);
* @% _* o/ a0 `0 o7 Preturn p;. w( T/ g2 s; @2 C4 U- Z! @
}  J1 f0 p9 \; h! b6 w

9 c) H- ~) m$ l9 v( U* U' G1 mchar * fun3(char * p)6 P/ O+ Z- I9 j% m5 M
{. r5 m8 s7 V# `! Y9 }
printf("%s\n",p);
. ^) S( T3 m: N1 `: rreturn p;; r+ @1 y4 `* m5 B& h8 M
}
2 h4 E6 e; f- T9 S, }" W
: g1 n! W- M$ Q' k% c" p' K! B: u8 z& i1 O% Q+ \
3 u' v5 Z, W4 U8 V3 V* M& k

0 M2 P- J! ]0 K8 ^8 \/ I3 |5 L/ `- P0 I5 M& U$ [( S. X
void main (void) {
- r0 u' o, A) `; L# {6 D  f8 m6 r* `0 S$ d! y$ O% v( q
char * (*pf[3])(char * p);$ m! n& F% y  l+ n8 ^
2 W' e) b( v; l3 E9 B
# \. z# N/ G* i, j8 e1 c
#ifndef MONITOR51
* u  C) K' T8 A  j! e, B    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */6 ~! l6 |% ^  ]2 p
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */* e' L! {, A4 A) M. A
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
) {, \- D0 V0 P- V3 E8 I, K    TR1   = 1;                  /* TR1:  timer 1 run                          */
# ~8 ]7 [  W& A! P& }    TI    = 1;                  /* TI:   set TI to send first char of UART    */7 G1 X7 A, E; C) O; r' ^2 \" _, a
#endif
' m: S, ~  k& l4 u$ u
! i; _8 t" N5 i6 i7 W
0 o# s9 c2 K3 \1 e: z5 S8 bpf[0] = fun1; //可以直接用函数名
6 Z0 i, x, ~1 p1 O, k; `* E0 lpf[1] = &fun2; //可以用函数名加上取地址符* r* }9 C- \$ Z6 ~5 Z  \
pf[2] = &fun3;7 f# ^# R. p( P- C. y+ Y1 L
pf[0]("fun1");* {. P! W) x; Y
pf[0]("fun2");8 O! J- [' h( T' e( b
pf[0]("fun3");: H( e# j. R" W
while(1);
" r# L# b+ D+ i: o
. P7 f+ ]- ?% ^7 o5 y: s}
& e/ C+ k* s( W% e1 i: a' P% e
/ m) @9 o+ D: {) O
% O" m% n- l  b( D8 m2 l4 @仿真结果:
9 E* Z7 Y; s; hfun1. E8 o+ G0 n9 M; E/ U! r7 x
fun22 l/ r6 T1 Q1 e: T
fun31 N6 P2 M, C: Z6 X

, k: z2 o+ Q2 N! g" U
回复

使用道具 举报

 楼主| 发表于 2015-6-21 16:05 | 显示全部楼层
本帖最后由 kenson 于 2015-6-21 16:12 编辑
. S% U9 ^5 H- k0 P' a
3 F$ e* w8 ]0 h! e; svoid main (void) {. ~( J' |3 ?/ y3 ^1 H. \7 F
    char * (*a[3])(char * p);& N  z, r, N; P
    char * (*(*pf)[3])(char * p);
; J. I+ d% C5 m( A/ e' ^2 _    pf = a;
: U2 V- Y& X  T% D- B- u1 A8 v; J8 Q$ M: W1 S' ]/ E" ?4 V
% w/ P1 g  i4 A% w. C8 S
#ifndef MONITOR51
4 @  w) N8 B( G3 A& Q    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */
1 f0 ~7 n! r3 v8 L    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        *// a& u$ H/ U4 q2 o
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
) P: J# p% G4 F' Y8 R- ~    TR1   = 1;                  /* TR1:  timer 1 run                          */
: K! @9 |. n) l    TI    = 1;                  /* TI:   set TI to send first char of UART    */
1 h& E) B( y( d$ @7 g% e& A#endif, L0 {* S( _* Z
! t$ _' j! q. M, n$ F) ]5 P+ S: s
2 d+ N7 Q  n2 a: [7 V) V
- u2 _& m" l4 t7 G
    a[0] = fun1;
. O  H& L  L7 Y& Q/ A1 U% W# F2 i; n    a[1] = &fun2;0 ^% G# V6 ~. N" x
    a[2] = &fun3;2 o: h. P0 a3 P! b+ _
4 m) y1 ^5 k# s6 {  J
    pf[0][0]("fun1");
$ U, h; k0 H* p. z5 w    pf[0][1]("fun2");
7 N; B! ?( C5 C  d2 ~/ {1 }  |. y* l    pf[0][2]("fun3");$ Z* `: Z8 y/ Y7 l0 H, w3 g

1 K9 a* H0 ]9 |$ w- Xwhile(1);
+ t& w8 ]; F4 X3 ?
# O, q- }1 d7 S% ?4 |5 R1 W, A) j}
1 M" d4 [/ U1 Y' Z  F3 [9 i5 t
1 Y7 u4 Y  _3 i5 e2 ?
8 W7 ]- ~9 w8 i/ c  A7 q& C4 H4 U
回复

使用道具 举报

发表于 2015-7-26 17:09 | 显示全部楼层
学习下,谢谢楼主。
回复

使用道具 举报

本版积分规则

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

GMT+8, 2025-10-28 00:53 , Processed in 0.037173 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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