一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
楼主: kenson

C 中复杂的函数声明

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

使用道具 举报

 楼主| 发表于 2015-6-18 12:44 | 显示全部楼层
xzp21st 发表于 2015-6-17 14:023 u. ]7 e1 n+ z/ t( {
看到这类代码就想打人

; V+ ]) l8 }6 d; `8 B, t! [# H你想往高层去走如运行RTOS系统这类的你也要对这方面要懂得一点。
回复

使用道具 举报

 楼主| 发表于 2015-6-18 12:51 | 显示全部楼层
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。: c  s: V9 o! r6 v; m0 H7 Z
网址:http://www.state-machine.com/$ n" W0 c0 e( J' n4 ?9 Z1 S7 I
极力推荐!!!
回复

使用道具 举报

发表于 2015-6-18 14:11 | 显示全部楼层
kenson 发表于 2015-6-18 12:51
6 \7 y8 }" X* {; D9 Q+ Q我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。
7 _4 K' }+ W  F) `; {; R: q网址:http://www.s ...

  v6 e. `: Y' s! B8 n这不是量子状态机嘛
3 L1 [. P! j  G" O; j7 L
回复

使用道具 举报

 楼主| 发表于 2015-6-18 14:50 | 显示全部楼层
xzp21st 发表于 2015-6-18 14:11
% Y5 N: H2 i4 A这不是量子状态机嘛
! @' \; P+ \+ J+ |) Q8 S& l
是的!怎样对这个熟悉吗?- I/ M* p$ \" I' i+ r9 Q7 K1 A
回复

使用道具 举报

 楼主| 发表于 2015-6-20 07:57 | 显示全部楼层
指向函数指针的指针6 e3 o; n" g7 T; o
typedef int *(*pfun_t)(int a, int b): V4 E+ F5 M7 l0 q' s$ U
pfun_t *ppfun_t = NULL;
回复

使用道具 举报

 楼主| 发表于 2015-6-21 13:45 | 显示全部楼层
1.函数指针的定义
2 L6 J% c, }0 |# H$ m8 R
  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
  
1
  
2
  
3
  
A) char * (*fun1)(char * p1,char * p2);
  
B) char * *fun2(char * p1,char * p2);
  
C) char * fun3(char * p1,char * p2);
  
看看上面三个表达式分别是什么意思?

) ?6 B6 k4 M, y+ xC)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。
1 E7 d( D4 q# M/ K/ |+ uB) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。
/ ^8 g7 J$ ?5 X8 hA) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
  
1
  
int (*)[10]  p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
  
1
  
char *  (*)(char * p1,char * p2) fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。^_^。
2.函数指针使用的例子

0 C- ?& G! e2 _5 [8 Q# ~( W- X  上面我们定义了一个函数指针,但如何来使用它呢?先看如下例子:
  
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----这是什么?
0 M- j- q" k- o. w: v; Y5 p; I
  也许上面的例子过于简单,我们看看下面的例子:
  
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;
  
} 
8 M  f' W( e8 B0 H8 N
这是在干什么?*(int*)&p=(int)Function;表示什么意思?
& V) \) q# b/ p别急,先看这行代码:
  
1
  
void (*p)();
这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。3 T  K3 T3 `# A2 V
&p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。& b/ E, [: J3 C$ k1 w( ~9 o9 h( h/ [6 i
(int*)&p表示将地址强制转换成指向int类型数据的指针。
: e& H  ~1 G% y3 t  v3 V- R" P4 f(int)Function表示将函数的入口地址强制转换成int类型的数据。
' W2 }8 j5 Q7 p5 g4 T8 L1 g分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。

$ {1 `$ Y" G8 c6 R9 _/ B/ T2 F那么(*p) ();就是表示对函数的调用。

$ Z3 M: n1 C2 u6 V" q讲解到这里,相信你已经明白了。其实函数指针与普通指针没什么差别,只是指向的内容不同而已。7 e4 S; G# G5 ^2 @
使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或者归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。
4.(*(void(*)())0)()------这是什么?

) ^1 t- N# I4 Y/ c  是不是感觉上面的例子太简单,不够刺激?好,那就来点刺激的,看下面这个例子:
  
1
  
(*(void(*) ())0)();
这是《C Traps and Pitfalls》这本经典的书中的一个例子。没有发狂吧?下面我们就来分析分析:
  
1
  
2
  
3
  
4
  
第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。
  
第二步:(void(*) ())0,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。
  
第三步:(*(void(*) ())0),这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。
  
第四步:(*(void(*) ())0)(),这是函数调用。
( t  L) b  }% d4 A6 X$ `! _6 a
好像还是很简单是吧,上面的例子再改写改写:
  
1
  
(*(char**(*) (char **,char **))0) ( char **,char **);
0 R# N9 _+ r9 j* I; y7 @4 S. @
如果没有上面的分析,肯怕不容易把这个表达式看明白吧。不过现在应该是很简单的一件事了。读者以为呢?
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.函数指针数组的指针
; f- Y- A% `8 O' Y2 ^
  看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。
, B0 s  n5 t: r& B1 J! g其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。
- B4 X8 Q' R4 \2 |' z, x! g
下面就定义一个简单的函数指针数组指针:
  
1
  
char *  (*(*pf)[3])(char * p);

) c; ]/ E* o2 T  y7 z注意,这里的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 | 显示全部楼层
大家可以用仿真软件仿真一下这个程序3 H# |! b) D- P  k

- ?$ B( O8 S  H  h1 C5 w8 v2 X& p- d0 x% p2 A
#include <REG52.H>                /* special function register declarations   */" u. C5 e; k: q7 Z/ k# V
#include <stdlib.h>                                  /* for the intended 8051 derivative         */
' e1 ?3 a' H! Z% u7 s5 z9 c#include <string.h>
6 d3 K. p6 z' |! i$ q#include <stdio.h>                /* prototype declarations for I/O functions */
9 I+ \  Z9 U& j: g/ g' v3 a% ^$ B" k; X) Y
1 n, y7 }' k: D, ]6 M3 s
#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */5 u. K/ T8 B* u- _3 M
char code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */
; U4 R' Q. \+ h% ^, Z, t1 l#endif                                   /* Stop Exection with Serial Intr.   */
8 k: y6 E; {$ x6 M0 k9 l                                         /* is enabled                        */
7 m9 B: J8 R7 Q4 R  @% N2 _2 |2 E7 ?
char * fun1(char * p)
, K; G/ W8 O8 k( X+ E4 s- ]. Q{" {5 ^1 i7 S* g( G( _
printf("%s\n",p);
: h3 I9 b+ b. \; wreturn p;) U5 R3 q* i3 M/ i3 N0 r6 W2 _
}4 z; l& }: s3 Y8 q! C( h2 f
  b1 k0 A: ?" h, F+ _
char * fun2(char * p)
0 x9 i' G, v: y5 K& b1 y9 y, N{
6 X( p- X1 s4 x( V( Iprintf("%s\n",p);
! M/ g  V0 O$ Y. F8 D! g' ireturn p;
4 |* O5 h, h6 V4 l}* ?' K" W% W' ^4 }3 ^; y) B8 Y
; I. {: }5 n. ?
char * fun3(char * p)+ M' w0 o; g+ x3 q
{
7 J  S% v6 n& V7 o& W( Xprintf("%s\n",p);/ l! h( _4 O9 v
return p;
  U: W0 a! m( w9 k( o- I8 Q}4 m+ j  o" J( w

- z$ O- C  _$ D4 ]2 {& ^
$ a# A- E8 {7 X8 h7 f! Y4 p  Y; e5 ^: {0 T4 v& C( E* i

/ _) n6 s; ~/ R9 E. l5 k( R& F/ ^, X! b6 y
void main (void) {
1 a+ o, @6 Q" f' o7 x/ E- {
9 ^4 @6 A2 w4 I8 \char * (*pf[3])(char * p);- R* M9 M8 L5 F4 D0 E

8 R  z' M5 J/ D  ~  a( _
+ Z& u" P: T0 [: U( x#ifndef MONITOR51( l/ S1 R) M- C0 ~; t
    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */
! f8 ^0 _7 I- {! ]1 t+ R    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */6 H' y; ~1 {  W* p
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
7 F6 n0 p5 d/ G. v- L    TR1   = 1;                  /* TR1:  timer 1 run                          */
  \0 Y1 U- Y+ [2 D: |; W7 x! S2 ]$ H: Q    TI    = 1;                  /* TI:   set TI to send first char of UART    */
/ k$ w% G' Y+ B  x6 K( r. V#endif# l- V1 @9 a/ J- q. i7 k
5 ]( h3 c% p* y. J& y
4 {8 X- l. }& Q. F" v, }$ @7 u6 X
pf[0] = fun1; //可以直接用函数名
, Z  O2 d2 }( [1 P1 o& rpf[1] = &fun2; //可以用函数名加上取地址符6 q7 B* g+ [5 G4 f: a8 l
pf[2] = &fun3;
4 p/ ~: g( G4 [6 Cpf[0]("fun1");
- j6 C2 U* y, \( Q6 a( |) Qpf[0]("fun2");
! Q! S/ p# x, K6 ^3 Q0 E7 j  V" f( Ypf[0]("fun3");2 c% r+ D# C- `' F2 a5 Z* j  E
while(1);: J7 L4 f+ j" a' C% x) ?: k) `

& V1 u% X5 E  i0 z}0 \5 O' K/ c! e! N) K

2 n0 B/ a  v# b. x; l
  X1 ]  F$ `+ J" G% c' [. n: ]+ h& l仿真结果:/ I6 T8 L0 t8 w7 X# c* S2 J; x! I
fun1! S! R, z  c- R
fun22 f/ X  |- m4 C: }$ ^
fun3" }8 {6 P: s+ a! ?# u# W0 X- u

3 p, p) ^6 f) B! l8 U
回复

使用道具 举报

 楼主| 发表于 2015-6-21 16:05 | 显示全部楼层
本帖最后由 kenson 于 2015-6-21 16:12 编辑 4 d3 i, P& l  h! G) J7 }" s

; y7 c8 n  `4 Q6 Jvoid main (void) {. a+ C  L  U& I* Z! |& X
    char * (*a[3])(char * p);9 r2 s6 Q  u$ P- _
    char * (*(*pf)[3])(char * p);& x+ \. O8 ?% h4 z9 `# X. t
    pf = a;
7 K/ i& X+ s( z# M/ J
7 `8 m, R4 B  j: |- o. G) e& r
  T- ?* i* Q9 G. S& p#ifndef MONITOR51
5 d$ I; u* @7 f; _. G    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */) c$ i6 p7 j5 A+ z
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
; e$ Y# K! y1 W" W    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */% U  j0 G, b; I( G/ D
    TR1   = 1;                  /* TR1:  timer 1 run                          */
9 m( X' y$ L) Y, ?# S/ t* V, L0 i    TI    = 1;                  /* TI:   set TI to send first char of UART    */
+ D* y: A* O, L/ @0 ^! j3 f# r#endif9 @  E" O4 o6 v, [

8 G! ?/ ?! P, s
6 C+ W8 c) U: g) U3 q0 P/ m1 @8 z
    a[0] = fun1;
0 a- }; Q1 e$ ?    a[1] = &fun2;  d  x2 N% L( _6 u2 d
    a[2] = &fun3;
3 Z: A- x' q3 ^
5 [! [, M# n. O    pf[0][0]("fun1");
. T) ^+ A' n( w/ V8 `% m9 B3 o: K    pf[0][1]("fun2");
; `6 [: n: Q, \7 c( x    pf[0][2]("fun3");
5 e6 r! ]( A. {; I! N, L7 D' R! Q5 x4 R1 N3 |. r: t. j
while(1);
) j0 |3 J) a% w: Y! {1 V
3 d# Z/ T5 [" b; R}
5 Z! a; B5 X/ D) s6 D* ^. b  K: Z. B# Z, |' V" z; d" G

3 L" `) Z9 N5 \9 G- _3 b+ k
回复

使用道具 举报

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

使用道具 举报

本版积分规则

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

GMT+8, 2026-4-19 16:27 , Processed in 0.035328 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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