一乐电子

一乐电子百科

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

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
楼主: kenson
收起左侧

C 中复杂的函数声明

[复制链接]
发表于 2015-6-17 14:02 | 显示全部楼层
看到这类代码就想打人
 楼主| 发表于 2015-6-18 12:44 | 显示全部楼层
xzp21st 发表于 2015-6-17 14:02) |; N- |3 E% Z8 H( Q
看到这类代码就想打人
$ v1 ^* G) G, S3 i* a' S& ~$ ^
你想往高层去走如运行RTOS系统这类的你也要对这方面要懂得一点。
 楼主| 发表于 2015-6-18 12:51 | 显示全部楼层
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。
& T' p% ^3 _9 X" y( l! b% P' l网址:http://www.state-machine.com/
3 A6 T- Y& x* n, B极力推荐!!!
发表于 2015-6-18 14:11 | 显示全部楼层
kenson 发表于 2015-6-18 12:510 d5 z9 g% ], a* Q2 e7 y3 E
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。
; t8 v4 A5 V% [" X+ j网址:http://www.s ...
0 L. |1 }, s" c# X2 W
这不是量子状态机嘛
9 L  `' V# j4 {
 楼主| 发表于 2015-6-18 14:50 | 显示全部楼层
xzp21st 发表于 2015-6-18 14:115 _+ ^9 s4 ^6 p. M
这不是量子状态机嘛

; G+ X/ V* Y% ]! r% T是的!怎样对这个熟悉吗?3 z" l0 l* Y' y1 ?3 h' E. a
 楼主| 发表于 2015-6-20 07:57 | 显示全部楼层
指向函数指针的指针
* ?9 H" F5 _- r% d- K1 G) Btypedef int *(*pfun_t)(int a, int b)  o% h$ ~. W, f; S! w; S1 D
pfun_t *ppfun_t = NULL;
 楼主| 发表于 2015-6-21 13:45 | 显示全部楼层
1.函数指针的定义

5 J/ U9 K2 O2 `3 S/ F6 w) f  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
  
1
  
2
  
3
  
A) char * (*fun1)(char * p1,char * p2);
  
B) char * *fun2(char * p1,char * p2);
  
C) char * fun3(char * p1,char * p2);
  
看看上面三个表达式分别是什么意思?
/ n/ S  q9 C! V) u$ G
C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。
) }- w# }. Z7 w- Y0 t$ gB) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。; N- G0 o6 C" l( T2 u2 t; U
A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
  
1
  
int (*)[10]  p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
  
1
  
char *  (*)(char * p1,char * p2) fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。^_^。
2.函数指针使用的例子

5 t( t5 C, m# 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----这是什么?
+ r" P. s( s! i% X# U
  也许上面的例子过于简单,我们看看下面的例子:
  
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;
  
} 

* x9 _# A1 a/ I) w  _1 c这是在干什么?*(int*)&p=(int)Function;表示什么意思?
# S# y- S* _5 j# K7 Z别急,先看这行代码:
  
1
  
void (*p)();
这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。1 S; c! ?; t- Q: V' O+ m- g
&p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。# D0 i# L. m3 c2 \0 d
(int*)&p表示将地址强制转换成指向int类型数据的指针。5 S4 Q% u, ^$ ~& f. A, C) E
(int)Function表示将函数的入口地址强制转换成int类型的数据。1 P6 x8 R7 H, Q
分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。
* D* Q3 a0 F! U. x& U" _7 z
那么(*p) ();就是表示对函数的调用。

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

, I0 z" a, {% I8 A- l好像还是很简单是吧,上面的例子再改写改写:
  
1
  
(*(char**(*) (char **,char **))0) ( char **,char **);
0 F/ z3 }8 [( E; W8 {* O9 ~1 h- I1 t
如果没有上面的分析,肯怕不容易把这个表达式看明白吧。不过现在应该是很简单的一件事了。读者以为呢?
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.函数指针数组的指针

1 @* S8 F) J" L  m( O7 |  看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。
3 ?. L8 N( n6 }, g其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。

# D4 {  E9 a! j& [下面就定义一个简单的函数指针数组指针:
  
1
  
char *  (*(*pf)[3])(char * p);
0 T/ q/ {! }  Q- E7 U" q3 }
注意,这里的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 | 显示全部楼层
大家可以用仿真软件仿真一下这个程序
8 E; _3 Q& _. H% C7 M9 D
1 s* l+ C% \+ v% H* t: p
5 d) p* G# v) a#include <REG52.H>                /* special function register declarations   */
3 ~$ R2 X2 g8 N8 Z( `#include <stdlib.h>                                  /* for the intended 8051 derivative         */
9 g( v' k* x5 ?; g2 S0 e) {#include <string.h>/ a7 }5 v3 h9 p! u: m
#include <stdio.h>                /* prototype declarations for I/O functions */0 h% h" M- V; X$ [5 u! g

: I( L' @1 k4 c1 h. c
1 y7 u- n' X$ s/ @7 X0 n! A#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */2 H& i7 b- g$ \1 c( u/ @
char code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */' f4 f8 z* V( S  d, D# |2 f$ U0 ^
#endif                                   /* Stop Exection with Serial Intr.   */$ V) V- r' X4 Z: d( _5 j
                                         /* is enabled                        */
% R/ `' v/ Z$ Z. P  }! S6 _7 u; g- i5 t$ H
char * fun1(char * p)4 y, N6 @. M" {+ s$ O" P) q
{+ ]2 ^  f" M4 v- {! c
printf("%s\n",p);+ d, {" y* W/ n$ k/ l
return p;. m4 U: V, A5 a* q4 ~% N
}
* [, u- B; q+ O. \2 f" S
/ \1 k1 ^' Q/ c2 O5 {' F+ f& Fchar * fun2(char * p)$ o$ A8 g# B# N( o# _
{& h- u4 ]9 n& K6 m* w- f
printf("%s\n",p);
& _9 o& ]  l% l& J6 S1 r$ kreturn p;: g8 T/ Q3 Q6 {
}
! `, N9 K8 i/ r' c; p& q% L# M) F! p( Y9 x! q/ ]; k
char * fun3(char * p): k0 l) X8 y! r: `$ {
{
0 }7 E8 J- e4 J( G$ \* I$ ?( ?$ Eprintf("%s\n",p);  ^( ]  z% g* C: l# }! q, C) h- u
return p;
$ j+ i' L- X, }9 ~% @+ s}
4 ~/ d  b; O3 I* M% A- D" [0 P3 h
/ o! l" S; ~/ a( ^9 F! c2 C: ]2 x
' ~7 }& F" ?+ d2 [3 A6 _

/ y5 }  E& c$ y3 o8 B( v4 M! [0 F) J6 E5 |' M. j/ l/ T
void main (void) {( T' F! k5 s7 z2 {% o. r

8 y3 m% X: k5 mchar * (*pf[3])(char * p);
) }% R- A/ O) M
  Z  T9 ~; s' Q' ~: g
6 F6 H; i  I1 A  F0 F8 ~+ h+ o* V#ifndef MONITOR51
8 B1 O5 _, G7 M: B  R5 J0 T    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */
- A9 w& W7 |$ a    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
6 h( `# J7 I, r2 g4 X/ Y3 K& i    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */: v, \4 l% m0 r  ~$ R9 h
    TR1   = 1;                  /* TR1:  timer 1 run                          */. [9 a/ s# {) a8 [0 v6 H7 B4 j6 b
    TI    = 1;                  /* TI:   set TI to send first char of UART    */) i) r: q& }! v" `
#endif
5 H# y3 \! ]9 V
5 H7 B& Q  f9 U, P( m$ `  J
, ~) m9 Z9 e- G4 E5 e! fpf[0] = fun1; //可以直接用函数名/ i( O4 T0 e4 z: y2 @
pf[1] = &fun2; //可以用函数名加上取地址符
  q2 G+ Z, W# ~/ [pf[2] = &fun3;2 r2 ~7 K  j' O1 h& @8 M9 ]
pf[0]("fun1");
! Q' Q3 b* `, H) ~& t' K# Ppf[0]("fun2");
8 p% V& K3 B- k3 ]: Epf[0]("fun3");* ~. e$ ^8 a0 E# F7 Q% [# H1 P
while(1);6 x2 [" u# y! x

4 N9 B& Z+ v& E7 e2 U}
/ C0 d# j" o) D- U$ g# V$ \2 E1 ]+ ?( z9 W3 ]! |2 y6 L

1 t0 Q( T' U$ A& A3 ?5 J& ~+ a. a仿真结果:' o2 s6 `6 F/ J9 Z  q9 @" q; S& T
fun1  g! |% v) R( h
fun28 }8 ~, j1 S9 U1 a  @; G
fun3
$ V* D7 t) v+ f- v# a* F( I7 \& [7 h
 楼主| 发表于 2015-6-21 16:05 | 显示全部楼层
本帖最后由 kenson 于 2015-6-21 16:12 编辑 0 m+ s2 ^  k4 Q

3 z9 t9 X! E7 d$ {0 W, \void main (void) {4 |  z9 C) v& ~4 m  t- y" z
    char * (*a[3])(char * p);
) h) G' B9 B+ k. F$ u    char * (*(*pf)[3])(char * p);+ R! N* R3 g6 ]: v/ w1 }* x9 j" `
    pf = a;8 Z+ |. @$ ~' S
8 O, r( P' k/ c+ C' n
1 A6 C4 {' }8 d3 g* J" x
#ifndef MONITOR51
2 k% c( `; m8 I$ [+ a    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */- m- r+ A# W5 [: v: @
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
1 _( D! Z6 y- g8 S: P1 J    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */0 ^# ^" E/ o4 d4 g
    TR1   = 1;                  /* TR1:  timer 1 run                          */* x- \3 g  l9 r6 T" h, ~+ H+ ~
    TI    = 1;                  /* TI:   set TI to send first char of UART    */$ }. r% y- B. A6 }
#endif" W3 ^( r; Z4 m( _1 }

  I9 u2 t& e) I: p. {7 }% \- Y
8 |/ E$ Z3 F, ]$ R* R* G% ~- j: b  T+ f  o( A7 o
    a[0] = fun1;
3 q5 j  ~. T! E& A. q    a[1] = &fun2;
( X0 F. n0 E% N- [; r    a[2] = &fun3;' |& G/ f1 U/ H" f: C+ Y
7 t& j: t0 o* z8 J( e
    pf[0][0]("fun1");- u3 `9 i. _: T6 C$ M7 d  e; m
    pf[0][1]("fun2");' A# F; T, ~9 r% Q# B6 m* _
    pf[0][2]("fun3");
" {3 p% `8 j% B2 m8 ^! m9 t
4 a' b6 c4 F. I" Z8 _  d; rwhile(1);( ~0 t2 U4 p+ r& |% }

7 h  F: o" H: h. [}$ B0 d+ N  I5 ^$ z  }! z' e* c

# E  F! g3 T* i  u
) |& q5 f9 ^  [0 S% x
发表于 2015-7-26 17:09 | 显示全部楼层
学习下,谢谢楼主。

本版积分规则

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

GMT+8, 2025-4-28 12:33 , Processed in 0.049025 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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