一乐电子

一乐电子百科

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

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
楼主: kenson
收起左侧

C 中复杂的函数声明

[复制链接]
发表于 2015-6-17 14:02 | 显示全部楼层
看到这类代码就想打人
 楼主| 发表于 2015-6-18 12:44 | 显示全部楼层
xzp21st 发表于 2015-6-17 14:02  y3 A! m/ T$ @5 i) ]; v* o
看到这类代码就想打人

5 |$ g; A6 C, {; Q% }你想往高层去走如运行RTOS系统这类的你也要对这方面要懂得一点。
 楼主| 发表于 2015-6-18 12:51 | 显示全部楼层
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。
1 r' R* w  _+ _* k+ U3 f* p网址:http://www.state-machine.com/
4 O- D" e0 m$ l5 q; V* P7 O极力推荐!!!
发表于 2015-6-18 14:11 | 显示全部楼层
kenson 发表于 2015-6-18 12:51
: {7 Q3 t# D# O* J# z4 ~我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。6 ~3 ^& b8 @% E  I
网址:http://www.s ...
8 N" ~9 G: ?( W$ C, c% @% A
这不是量子状态机嘛: L4 {# ^5 B" s
 楼主| 发表于 2015-6-18 14:50 | 显示全部楼层
xzp21st 发表于 2015-6-18 14:11$ s& u' C6 z6 Y
这不是量子状态机嘛
1 g3 `* p0 [. I
是的!怎样对这个熟悉吗?  U6 N0 S& i; F+ f: C0 p- ^- p; U
 楼主| 发表于 2015-6-20 07:57 | 显示全部楼层
指向函数指针的指针$ ~. n3 h7 g- G" P8 f; V
typedef int *(*pfun_t)(int a, int b)5 I7 ]( ]0 q0 ]
pfun_t *ppfun_t = NULL;
 楼主| 发表于 2015-6-21 13:45 | 显示全部楼层
1.函数指针的定义

4 g' P0 r- ~% m0 h8 X  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
  
1
  
2
  
3
  
A) char * (*fun1)(char * p1,char * p2);
  
B) char * *fun2(char * p1,char * p2);
  
C) char * fun3(char * p1,char * p2);
  
看看上面三个表达式分别是什么意思?

' F- Q) ^7 A: fC)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。- I3 |- e' T3 s2 K3 W' {
B) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。: G8 i' h1 m- n' a
A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
  
1
  
int (*)[10]  p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
  
1
  
char *  (*)(char * p1,char * p2) fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。^_^。
2.函数指针使用的例子

" M1 N$ T) k$ j2 m2 X; i8 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----这是什么?

! Q; V5 f4 P; L9 O0 d# S  也许上面的例子过于简单,我们看看下面的例子:
  
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;
  
} 
/ }6 f' p* |# I$ K  ^: `
这是在干什么?*(int*)&p=(int)Function;表示什么意思?, r$ A/ ]3 d% R4 d
别急,先看这行代码:
  
1
  
void (*p)();
这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。
2 z, T# k0 p' _* r, O( G&p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。
6 x# h* o3 F4 c7 G1 V, c(int*)&p表示将地址强制转换成指向int类型数据的指针。
1 k6 ?  T; V0 j3 N8 b+ S(int)Function表示将函数的入口地址强制转换成int类型的数据。
/ D3 k4 l) ]$ S分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。

3 W- @+ z9 W5 J$ r, U+ w1 }那么(*p) ();就是表示对函数的调用。

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

) Q( n( e, \( i好像还是很简单是吧,上面的例子再改写改写:
  
1
  
(*(char**(*) (char **,char **))0) ( char **,char **);

' E1 b3 s' g7 h+ C如果没有上面的分析,肯怕不容易把这个表达式看明白吧。不过现在应该是很简单的一件事了。读者以为呢?
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.函数指针数组的指针

2 L' e' K4 l+ o% ?( K  看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。
! w" j  ?( |! W其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。

  \. c/ _4 x5 Z: B3 B; x6 ]( l% \! V* P( Y下面就定义一个简单的函数指针数组指针:
  
1
  
char *  (*(*pf)[3])(char * p);
! ?: A3 S7 i$ }2 J8 R, C
注意,这里的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 | 显示全部楼层
大家可以用仿真软件仿真一下这个程序
# ~6 t+ N& g$ l3 X5 {
1 L/ |( P& _' ~5 p" t' D& [+ q
) l: j4 c2 T1 n0 k0 v. a#include <REG52.H>                /* special function register declarations   */
9 w2 {" V0 s; R#include <stdlib.h>                                  /* for the intended 8051 derivative         */! N9 B" K+ L2 t& h
#include <string.h>
, W2 V5 f8 n; L: [# b#include <stdio.h>                /* prototype declarations for I/O functions */
( c% }" B- z, Z5 T. r2 y$ C  Z
  W1 K. R# F- H' e8 ^8 D* a+ Q! k, d; g* s* m, T- V) x: @$ n
#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */5 G. L9 J* [- k% n+ D* `  m& |
char code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */
  h6 Z3 {4 w& n3 `$ b8 c1 P) w. b#endif                                   /* Stop Exection with Serial Intr.   */" l- c5 c8 S: P6 j, s$ V
                                         /* is enabled                        */4 L! J; O, [9 d. B8 e

' h( d5 O: N$ H$ x  _char * fun1(char * p)
) }7 g8 \! V4 Q. ~$ J{
0 L1 O: d$ {; k  j6 Gprintf("%s\n",p);0 C5 d% E$ O, u4 J2 O9 V8 C
return p;- ]! [7 j. B$ U- n# p$ D% {
}
* z5 y+ [, G! I0 r( I9 \9 L* t" L+ I& j7 X9 t/ K% _/ V  i# X
char * fun2(char * p)
+ }1 D/ S+ z8 l2 E7 w0 h. a{
' ~, [# X& Q5 Bprintf("%s\n",p);9 W; j+ C$ B: h$ \! `: h
return p;  J+ {' r) u0 Q, K% Q1 D
}
1 S- d4 A8 R9 Q& e* @. U9 O
: T1 D1 b0 _' m1 ochar * fun3(char * p)
1 z  f: i2 l9 [+ @: [" {* P{% M* P( A: R' P! u, D
printf("%s\n",p);
& t& W  }8 T2 j  u- w: n$ ]4 Kreturn p;  N5 m, q" U5 Y: B4 x
}
) q, M% y, B4 [# @# |# X- e. T  R
& P6 j1 z2 x0 a# z+ V6 y" [. _
7 ]2 A+ S$ V1 M
3 ~# T, H  c4 Z+ Z& j! A" S- L+ E, f$ f8 x! f- m) S

) W' w2 |! P5 I# x4 _4 Jvoid main (void) {
, ]% K8 s( c4 I' \( ~3 N8 Y8 A2 ^6 b* W# N! u3 ]
char * (*pf[3])(char * p);6 u# O! c- h# L) g+ z

& b4 r+ S, X$ C- m# G, c4 N3 p$ Z2 R3 H* W) y
#ifndef MONITOR51
$ ]" x# p4 U4 f! c7 v- Z    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      *// F# ]/ q) d& O: r* _* ~! C: y
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */) e5 k4 j- d  G: }0 S- g( ]0 U
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */2 {8 k. Z1 O0 G( c9 \
    TR1   = 1;                  /* TR1:  timer 1 run                          */
- K: `+ D, f( j+ c  }$ u* ]3 Z    TI    = 1;                  /* TI:   set TI to send first char of UART    */
. \9 s, L+ G) e  `. @#endif
. S# k' _) Y8 w: J3 s. b7 A" J
  J  K) Q. Q$ a+ C
% o5 j6 c& v2 [pf[0] = fun1; //可以直接用函数名8 N; O. g. h* k% K. q9 Q
pf[1] = &fun2; //可以用函数名加上取地址符3 N5 [# }- ^2 N' `
pf[2] = &fun3;
# H  w4 D0 V6 e, z0 wpf[0]("fun1");
) C* o* K/ g$ J( g6 `pf[0]("fun2");" }1 ]) N. Q  r* ^
pf[0]("fun3");* Z1 u7 U$ W7 C) w
while(1);
+ z. U& `: a) m3 ^  I! {. V- P. U: T" l+ m1 V" c& v& h/ x
}
+ k% p/ ^: z2 x: t5 A! H8 S  M5 V5 {1 g: a

0 R* l9 e; x0 E; l, B仿真结果:! `. O6 j5 @7 [# r
fun1
4 T: z6 Y. e6 I, @fun2; G+ o( P% L3 C9 j3 \3 v: G) d
fun3/ E$ h+ w9 E  ]+ y1 n* Y
, Z2 A' _3 X# s6 s6 o, r
 楼主| 发表于 2015-6-21 16:05 | 显示全部楼层
本帖最后由 kenson 于 2015-6-21 16:12 编辑 2 Y6 W2 L1 n: O2 v' \
* s& \( e4 n% r" K( O
void main (void) {
/ j( U# B/ I5 a: `3 Y0 D0 n6 w    char * (*a[3])(char * p);' t% j4 F" o+ t
    char * (*(*pf)[3])(char * p);
) _' C4 w% L- q& S: R# i5 [4 l) R    pf = a;# k3 J! \5 r+ T
: O: \' M4 T0 f" y. v4 e9 O

& x5 H# }  }/ i; V9 M3 j. Q0 O" c#ifndef MONITOR518 u: p- W' R' `: N9 S9 V
    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */. l! K0 r9 P& Q& B% e& N9 T- g
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
  \. Y& C! Z( f- N    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
0 @( _  }8 I3 w    TR1   = 1;                  /* TR1:  timer 1 run                          */
) W2 K& A3 p9 l2 m" u3 D3 @" g$ [+ H    TI    = 1;                  /* TI:   set TI to send first char of UART    */6 C* U' o1 t% p
#endif0 `" R3 z+ C1 O# }
6 Z  v2 [% u( x. D2 ?( A0 R/ S' j
# V4 P: M) Z. `5 l

: s8 J" G% u' j4 k& P' z    a[0] = fun1;
4 [' ^1 r: F0 W    a[1] = &fun2;
( W9 V+ ^- x* f" `9 s    a[2] = &fun3;
  @) C! `1 [' o4 O/ X; _. i9 k7 \
; F4 Y$ I1 e  z    pf[0][0]("fun1");8 v% m% V. d+ }& z' q. F
    pf[0][1]("fun2");
' N2 ]% c% g, F6 j# P; {0 {    pf[0][2]("fun3");% e" Z& ~' ^2 y. v" h
8 K, j2 A& t- q: P" r. u2 z
while(1);
* i0 E& A) l3 q  b* q
1 {" J, M- @: X' R% g2 m- V, j5 i}
! }' d# S/ j1 {; g# A2 D2 ]
1 A8 o( d! Z9 A9 @( [
; e4 t' ~7 k8 Y4 q3 n' u2 B( v8 t* o
发表于 2015-7-26 17:09 | 显示全部楼层
学习下,谢谢楼主。

本版积分规则

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

GMT+8, 2024-5-11 00:59 , Processed in 0.054577 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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