一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
楼主: kenson

C 中复杂的函数声明

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

使用道具 举报

 楼主| 发表于 2015-6-18 12:44 | 显示全部楼层
xzp21st 发表于 2015-6-17 14:02
. S/ H$ j5 ]- @5 d. N$ q0 y6 \看到这类代码就想打人

1 @6 ~2 w1 t0 G, k7 e6 r你想往高层去走如运行RTOS系统这类的你也要对这方面要懂得一点。
回复

使用道具 举报

 楼主| 发表于 2015-6-18 12:51 | 显示全部楼层
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。9 N1 C' i0 x1 v0 t
网址:http://www.state-machine.com/3 c1 ^2 Q" x$ e' J( [
极力推荐!!!
回复

使用道具 举报

发表于 2015-6-18 14:11 | 显示全部楼层
kenson 发表于 2015-6-18 12:512 ?8 t3 x" f* h- L/ N" T% k
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。# `5 j9 ?3 E+ u! f# Q, J8 d0 a
网址:http://www.s ...

" Z0 Z$ {: |' D7 s+ k这不是量子状态机嘛
3 x+ W- r" T) Z* J2 b: ]/ |
回复

使用道具 举报

 楼主| 发表于 2015-6-18 14:50 | 显示全部楼层
xzp21st 发表于 2015-6-18 14:11* S( @/ f* l6 Y( q
这不是量子状态机嘛
, ^) ~  u  X7 W  E) h! P% P' L
是的!怎样对这个熟悉吗?
, J+ U7 T  W) |& p6 i
回复

使用道具 举报

 楼主| 发表于 2015-6-20 07:57 | 显示全部楼层
指向函数指针的指针
" J( R5 w2 ?5 M$ c; M' ]typedef int *(*pfun_t)(int a, int b)
. N' \: `. F$ m' Spfun_t *ppfun_t = NULL;
回复

使用道具 举报

 楼主| 发表于 2015-6-21 13:45 | 显示全部楼层
1.函数指针的定义

) ~, l  H/ w4 s, N/ a  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
  
1
  
2
  
3
  
A) char * (*fun1)(char * p1,char * p2);
  
B) char * *fun2(char * p1,char * p2);
  
C) char * fun3(char * p1,char * p2);
  
看看上面三个表达式分别是什么意思?

7 q) x( E  \) Y% `& V( XC)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。3 J) x# H0 D3 E, G2 W8 }/ i
B) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。2 W  t2 Y* V9 ~* _9 Z6 ]- ^$ U* a  S. r
A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
  
1
  
int (*)[10]  p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
  
1
  
char *  (*)(char * p1,char * p2) fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。^_^。
2.函数指针使用的例子

, M! z4 E' q( \( B% ]  上面我们定义了一个函数指针,但如何来使用它呢?先看如下例子:
  
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----这是什么?
& D+ K. q4 ~6 Y( H9 E6 e
  也许上面的例子过于简单,我们看看下面的例子:
  
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;
  
} 
! ?( y1 D- v0 t' w3 ~
这是在干什么?*(int*)&p=(int)Function;表示什么意思?6 W/ {9 M9 J3 }1 z* A4 V) ]
别急,先看这行代码:
  
1
  
void (*p)();
这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。
& N* i. _* u4 {7 O8 s&p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。; R& Y$ k0 x  V  L& ~
(int*)&p表示将地址强制转换成指向int类型数据的指针。
& C, x. }6 j5 U# ?( u3 V% d(int)Function表示将函数的入口地址强制转换成int类型的数据。9 ?& n! V6 D. F
分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。
. B" p3 v' A5 }2 D
那么(*p) ();就是表示对函数的调用。
# D' S  V. A; p7 f) Y
讲解到这里,相信你已经明白了。其实函数指针与普通指针没什么差别,只是指向的内容不同而已。
  w3 J! b1 i' |" b4 A使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或者归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。
4.(*(void(*)())0)()------这是什么?

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

! C% R$ ]/ R6 Z好像还是很简单是吧,上面的例子再改写改写:
  
1
  
(*(char**(*) (char **,char **))0) ( char **,char **);
- K# N9 q% h- A/ ^6 b% J+ I
如果没有上面的分析,肯怕不容易把这个表达式看明白吧。不过现在应该是很简单的一件事了。读者以为呢?
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.函数指针数组的指针

0 n0 I/ D) H+ C, [  看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。( B% ]" W* y5 R5 |! G
其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。

& U& t' I5 R$ P0 O4 D4 ~/ @下面就定义一个简单的函数指针数组指针:
  
1
  
char *  (*(*pf)[3])(char * p);
5 e9 D- D0 A6 F1 W
注意,这里的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 | 显示全部楼层
大家可以用仿真软件仿真一下这个程序
2 o* G+ J7 Z8 m% Z' ?$ h( ?' @4 J8 v  m
7 z" X( `) _7 I5 ~# D3 |$ M4 ]" B0 @' R3 l4 E. o2 M% x: a6 C: O' l5 {
#include <REG52.H>                /* special function register declarations   */) t. `5 n+ u2 n5 t! Q9 q
#include <stdlib.h>                                  /* for the intended 8051 derivative         */
, ]3 S  }$ S7 |3 {#include <string.h>, l  l# Q: @( M% x5 A, n/ b
#include <stdio.h>                /* prototype declarations for I/O functions */% [/ g* {  ], o% ]6 }4 Z

! j7 f5 y- F+ q0 e2 X, j5 n) p; L. I% Q1 ^: w/ l* F) K
#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */
$ p8 u0 B. C' N8 i  Tchar code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */
* a. ~' j( Z+ Z" B1 W4 j' T* w#endif                                   /* Stop Exection with Serial Intr.   */
, D4 V; z; X1 k3 O* f/ K% |7 k                                         /* is enabled                        */
. f1 b6 l, z) U8 d+ _3 H5 O: e& ]9 a" G3 X
char * fun1(char * p)* s/ b) j2 X& J) m& q
{- ^( T: ]3 @. p1 E
printf("%s\n",p);  K5 p: \# j5 D+ v
return p;3 D6 {) Z5 e; v$ P$ v' Y
}
% i1 b# \6 b8 f" C1 i  d0 C4 h" u. Q: P5 i$ t* D3 m
char * fun2(char * p)# M) X% Z4 `( @2 N
{
2 m0 x- s& ]* k7 W8 Q5 Tprintf("%s\n",p);
, i8 B( I* b8 A5 @8 w3 W  freturn p;4 O; ?8 K3 R0 Z, }4 ]
}* F& I7 d7 G. G: N

' l0 D& d2 k  s0 p$ q# Y- {% a) Uchar * fun3(char * p)
! _9 M" Y3 r8 [& t4 \4 U{- _1 u9 t7 H7 x- i+ L9 q
printf("%s\n",p);
7 o1 S, h* @& P9 W8 P) rreturn p;( Q2 ]$ F; N' H' p/ @7 V7 g
}: S4 S# c- l9 y. Q* Q, d( x

% X6 J* I& S. g' n' l, w( s: B* _

* J$ A: N, O7 l6 \- H- }4 f
7 I* |/ q9 a! t$ f4 @' B7 Q9 P! |( D: k
void main (void) {
/ W) i) c4 D+ Z: E. u7 d1 p, O
0 c& N. d- \, F4 {8 {* jchar * (*pf[3])(char * p);! ^* F+ s2 d! x2 @2 W; {) ^% E2 r
0 V+ e" Q0 S9 A' Q

. H, P. B4 b5 I& {$ J#ifndef MONITOR51( h# m  |8 h- _7 g/ Y
    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */
4 p) W+ l6 e6 t    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */" B0 c9 Q3 J# u: i8 M* s; y9 b
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
) p' O2 |3 R* _1 A* z! Q    TR1   = 1;                  /* TR1:  timer 1 run                          */4 D" L) ?; H# P/ `6 N8 K4 p' K' V
    TI    = 1;                  /* TI:   set TI to send first char of UART    */3 y1 c6 v9 x/ a' @
#endif0 K0 q0 D5 g( R( w) q
9 }4 f, b' \2 Q8 y. J  z
& w, \* Y2 y$ }+ b  P* A5 a
pf[0] = fun1; //可以直接用函数名
, ~. q# E2 `+ jpf[1] = &fun2; //可以用函数名加上取地址符: B$ R; @! n" q5 l' M( w3 J( v
pf[2] = &fun3;
$ z7 W* U* g. Kpf[0]("fun1");
& n. M+ W. U* w! rpf[0]("fun2");
( [, _; g& X9 B! p1 Z8 Z* [pf[0]("fun3");- U- R$ A; j8 M  R: i$ e5 s  e* t8 R
while(1);
( y5 l  u# q& Y% h: U; ^5 [# ]" v6 L' S8 J4 s3 }
}4 q, t' C5 L. k6 F, l6 z6 J
  Q! N! v: g; z; o  W% ]9 d* k
; D0 x/ `! S; z, }
仿真结果:
" o5 L# y, g# j% L6 \1 x( O1 {fun1
+ V: K' F; p; x% l! O6 Nfun2
- \( m9 a0 H( J7 hfun30 G8 z9 V' `8 A, j
' _* E0 z) _2 j* j/ ~# I, p" W
回复

使用道具 举报

 楼主| 发表于 2015-6-21 16:05 | 显示全部楼层
本帖最后由 kenson 于 2015-6-21 16:12 编辑
! H5 `5 T" @. x3 P9 Q* i& o  x. N5 P+ g
void main (void) {, K$ J6 N+ g: S) y
    char * (*a[3])(char * p);
8 ^4 e- r3 s0 R, M# W    char * (*(*pf)[3])(char * p);* B. O7 K$ u% m- ~" C
    pf = a;
+ m; y2 w9 s: _7 N& W
& }0 y9 ~- ]3 [5 u: ]; ]6 j# e$ D( ~6 |0 C' Z
#ifndef MONITOR516 i( H8 _* m3 W  Q1 Y9 n( u; T: l
    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */$ }, Z- C% D0 z* T4 B3 I6 M& z4 m
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */  D1 ]' o$ u, P/ D2 I9 D. L4 j
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */0 {6 T. l5 u; T' S  v2 |) G
    TR1   = 1;                  /* TR1:  timer 1 run                          */
/ M' \( s* J6 B7 s& ~    TI    = 1;                  /* TI:   set TI to send first char of UART    */' a8 A5 O9 M5 Z% f
#endif+ R! ]2 E9 Y( i% M" h
+ @3 C9 _. t% ?2 j6 G: I

1 _$ `  e  C" L% Q' p5 |$ ^8 u( r7 X2 I- {+ Q. m
    a[0] = fun1;
" j% _/ |+ K( @+ j    a[1] = &fun2;6 F+ d. V$ U' G
    a[2] = &fun3;
( m' R( E" a; P/ f  Z
5 ^( v4 m# S" C) Q) D9 {    pf[0][0]("fun1");
" `/ l+ J$ s, W: U( ~    pf[0][1]("fun2");
5 ]2 }5 l! |' y& Q3 V9 m; q    pf[0][2]("fun3");) i) f7 k/ n6 S; H1 Z8 W
6 `7 I, Y/ H# c& k
while(1);, @" y+ O2 L- q$ x4 ~

+ [( f& g/ |2 [}+ n: S! Z$ \4 x7 _  @
, X9 [4 Q3 l8 C# t0 |
# s8 J" b) s9 ?# G- x3 R* n# w
回复

使用道具 举报

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

使用道具 举报

本版积分规则

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

GMT+8, 2026-2-25 15:04 , Processed in 0.035909 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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