一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
楼主: kenson

C 中复杂的函数声明

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

使用道具 举报

 楼主| 发表于 2015-6-18 12:44 | 显示全部楼层
xzp21st 发表于 2015-6-17 14:028 S$ G% k$ E; E7 N
看到这类代码就想打人

' S, f/ Z' ~: f, n$ U* z3 O你想往高层去走如运行RTOS系统这类的你也要对这方面要懂得一点。
回复

使用道具 举报

 楼主| 发表于 2015-6-18 12:51 | 显示全部楼层
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。! j0 Z- j3 u7 I+ g* l& A4 r- W* ~
网址:http://www.state-machine.com/
; I6 J/ v# d2 D极力推荐!!!
回复

使用道具 举报

发表于 2015-6-18 14:11 | 显示全部楼层
kenson 发表于 2015-6-18 12:51% J) W; e" M# `  a0 ?$ i
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。+ [; p7 a% ^! s4 V6 E; \  k
网址:http://www.s ...
. F7 S* C! ~5 o% G- y- |+ H
这不是量子状态机嘛
6 _. U2 a2 H# r- G9 C: B- D
回复

使用道具 举报

 楼主| 发表于 2015-6-18 14:50 | 显示全部楼层
xzp21st 发表于 2015-6-18 14:11
0 V+ G; d% j+ h& |这不是量子状态机嘛

& m( x- A" [' J. [+ D是的!怎样对这个熟悉吗?
, c$ r( r' ?, F4 ]2 \6 y
回复

使用道具 举报

 楼主| 发表于 2015-6-20 07:57 | 显示全部楼层
指向函数指针的指针4 E7 x# O" V6 Y2 F! U
typedef int *(*pfun_t)(int a, int b)
3 l# Z+ K/ b9 S, H/ o3 T1 lpfun_t *ppfun_t = NULL;
回复

使用道具 举报

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

8 Y$ P4 v4 B5 }7 f& x; g  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
  
1
  
2
  
3
  
A) char * (*fun1)(char * p1,char * p2);
  
B) char * *fun2(char * p1,char * p2);
  
C) char * fun3(char * p1,char * p2);
  
看看上面三个表达式分别是什么意思?

& g. p  ^( n8 gC)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。
# ?7 l$ l4 G! \* {5 KB) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。
3 f# S; g  |$ M1 L3 D& C4 v6 HA) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
  
1
  
int (*)[10]  p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
  
1
  
char *  (*)(char * p1,char * p2) fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。^_^。
2.函数指针使用的例子
5 w6 r8 \1 L1 |9 g
  上面我们定义了一个函数指针,但如何来使用它呢?先看如下例子:
  
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----这是什么?
3 V4 Z% G# p& M' l% }/ 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;
  
} 
9 B. a5 P, i- Z' t+ d
这是在干什么?*(int*)&p=(int)Function;表示什么意思?
! e4 c4 m& T' O* o& X别急,先看这行代码:
  
1
  
void (*p)();
这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。- i# W, Y5 s/ o% ^9 x
&p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。  X/ Z  X  j5 ^" M) i: R' [
(int*)&p表示将地址强制转换成指向int类型数据的指针。. u% Q7 q* U/ a3 o6 r2 n* n/ l
(int)Function表示将函数的入口地址强制转换成int类型的数据。( p0 K9 c" k' @, @% A8 U
分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。
. `/ L2 `  i7 {/ y( q
那么(*p) ();就是表示对函数的调用。

  B5 e3 f6 ^( E* P# G讲解到这里,相信你已经明白了。其实函数指针与普通指针没什么差别,只是指向的内容不同而已。) ^( v, y2 H3 q" p
使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或者归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。
4.(*(void(*)())0)()------这是什么?
- o' V# B/ W/ P. a2 x0 N& o
  是不是感觉上面的例子太简单,不够刺激?好,那就来点刺激的,看下面这个例子:
  
1
  
(*(void(*) ())0)();
这是《C Traps and Pitfalls》这本经典的书中的一个例子。没有发狂吧?下面我们就来分析分析:
  
1
  
2
  
3
  
4
  
第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。
  
第二步:(void(*) ())0,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。
  
第三步:(*(void(*) ())0),这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。
  
第四步:(*(void(*) ())0)(),这是函数调用。
  }% S+ {, L4 w4 W
好像还是很简单是吧,上面的例子再改写改写:
  
1
  
(*(char**(*) (char **,char **))0) ( char **,char **);
: f/ K8 j. \8 I" i# r
如果没有上面的分析,肯怕不容易把这个表达式看明白吧。不过现在应该是很简单的一件事了。读者以为呢?
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.函数指针数组的指针
# p2 U7 b. G2 _; M" h7 N9 u
  看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。2 B8 ~4 J3 A- `  g- u; {( @
其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。
$ I# R# G7 x9 x1 [
下面就定义一个简单的函数指针数组指针:
  
1
  
char *  (*(*pf)[3])(char * p);

3 u6 m3 [8 p; i. v* O) `9 s注意,这里的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 | 显示全部楼层
大家可以用仿真软件仿真一下这个程序$ c" \" |  c- w  t) m* Q

, Z' `4 N# P9 E5 D, f
% j. j9 M6 J) r+ n#include <REG52.H>                /* special function register declarations   */
! f/ v1 Z8 a, W! ]3 h0 G- s#include <stdlib.h>                                  /* for the intended 8051 derivative         */
+ \* h+ r/ ~$ B7 D+ R& o7 ?#include <string.h>
0 ^4 p3 B' t& c* e( B/ b#include <stdio.h>                /* prototype declarations for I/O functions */2 E! }- k; \9 \- O6 n# Q% `
; ~& O5 U4 [/ Q: [
9 _4 r0 ~% N8 @) R
#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */' u- Z, d, S8 ^
char code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */' u. U; u# _0 B( C6 H  q
#endif                                   /* Stop Exection with Serial Intr.   */! d8 |6 ^( r. N! K
                                         /* is enabled                        */
0 g  M! l. t# c& F6 [0 A" f
$ N' O$ O, ?* y: E: p2 ]2 V/ nchar * fun1(char * p)2 Q$ j8 n! q( {" G! r8 M
{
  p% |$ N5 Q- k4 Iprintf("%s\n",p);
/ x# I, y" j6 `) K7 I: sreturn p;& w) M( m  o7 Z) G+ F0 S
}
; x! o$ [3 Q9 e6 K/ w
9 ]! y  b$ E$ o5 D  Wchar * fun2(char * p)
9 d& B6 Y+ M0 P1 [3 P. ^  Q- z/ n{
3 i( l+ {1 T) y) Y$ C) j+ |. rprintf("%s\n",p);
, [, H4 h9 e6 h' o$ @return p;6 _" _8 L$ b2 E
}
- }6 A7 l+ c" K- c4 _! T; K
+ Y- K0 C% s4 k1 Gchar * fun3(char * p)4 |+ {* |% J1 r) z6 Z0 N
{9 w7 n' p' V* d7 {  C; ]3 k, ~: w
printf("%s\n",p);2 l: S* O2 j5 b4 y6 q. b; E, }
return p;* K  a, e* {4 }% @6 \
}) ~  K1 d. W1 K
* T3 B9 `- {& a0 J/ v

) h1 v1 N  P' f
# g/ j& J9 o  n5 x4 {$ b- v  P$ k0 b/ i+ s% J" L
3 J. a* C! j5 `  t" z3 G8 T
void main (void) {
+ F% o5 C" y4 F6 ~- A% O8 X' G" a5 b
9 e( g6 }. U( S0 bchar * (*pf[3])(char * p);
$ D, G" W, i* ]/ n6 K  h" l& P; v; f& e- H: \* F, N

  o' N* P0 K! D5 I- \9 \#ifndef MONITOR519 _, S1 u9 w+ S  t" F
    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */
' R* v9 K- a( s    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        *// w$ S% x8 y3 M7 H% K
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
, O) ?2 ^' H1 u- @* A/ u    TR1   = 1;                  /* TR1:  timer 1 run                          */0 Y* N: n: x  t* ?* T
    TI    = 1;                  /* TI:   set TI to send first char of UART    */
* G: [3 ]% R& @. z* Q! w0 ?#endif
) X/ q# ?9 Y0 ?1 h8 ^/ Z8 p: E3 v+ R$ c$ ?. v2 \

9 E. ~& o& _- O. I4 H9 L) }1 epf[0] = fun1; //可以直接用函数名
4 E/ k2 t2 U! |6 {( ]pf[1] = &fun2; //可以用函数名加上取地址符
1 x# b6 {6 B/ r3 U0 Zpf[2] = &fun3;+ F) Q" O/ g/ B: Z8 X
pf[0]("fun1");
; L* X; ^9 N  I, f$ t, h- xpf[0]("fun2");& y' N6 ?8 ?$ ?8 W2 ~
pf[0]("fun3");7 k* Q) R# H- V1 ?. \
while(1);
1 h( R1 s, S: M# X9 C; E) c0 M9 d  ~
}
* `) n( A) m0 w( o3 r7 U) m1 B" d7 W+ O5 Q: m  S& l' [' a

/ X" R2 n" Y5 E$ D仿真结果:& b, _( O' r1 ^& N7 x0 i
fun1! |3 X$ E6 L$ f1 E7 ~: V/ J
fun2$ i6 k' E% s; ~& j# X8 z& {/ N
fun3  S0 ^6 x! v' Q  r' o
$ a8 g8 {; O  F9 {$ l
回复

使用道具 举报

 楼主| 发表于 2015-6-21 16:05 | 显示全部楼层
本帖最后由 kenson 于 2015-6-21 16:12 编辑 2 q; m4 ]& X" Y
! t% \, j$ I) O0 k( }
void main (void) {
! a: ]( v2 N2 a6 O2 G/ C    char * (*a[3])(char * p);! _, z3 `/ {& S, i
    char * (*(*pf)[3])(char * p);
+ B; ?: }& Y$ d% E2 L' y    pf = a;
+ t6 Q$ S* f1 n, W9 x
; E: I  Y6 ?5 |1 y1 a0 s4 }
% r: Y4 y  S; c$ M#ifndef MONITOR51
" p0 B! f# o) R! E) _, w    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */
* m0 F( F' e" B    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
0 |9 @7 l& D8 n9 U1 \4 _9 |    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
; Y# W# s, o0 i/ P8 g! h1 D5 i1 k9 P    TR1   = 1;                  /* TR1:  timer 1 run                          */
$ U; e  J5 ~9 O' D% ?/ a$ @$ r    TI    = 1;                  /* TI:   set TI to send first char of UART    */" c: D+ C. h8 t5 z0 [  |: `
#endif: ?/ g( I* V4 n+ P6 z( H

( _+ P$ y% R( a$ c9 A
. p/ K/ ]( t# H! {
/ D: L) Z+ L/ f: U/ m2 A) B. j    a[0] = fun1;
& C' ^# r9 m* j. @% C" K7 O% a  p    a[1] = &fun2;
. K& _4 b6 `0 J' s9 i1 Z    a[2] = &fun3;
2 b6 `- p6 G1 {% {; L. K
  `, X5 A+ j/ V7 E3 Z4 b5 ~& p) o    pf[0][0]("fun1");
1 k4 N% K  T) ?  T. I$ O" h    pf[0][1]("fun2");9 @" z0 |6 D& ?/ A
    pf[0][2]("fun3");
2 k$ h) K& [: D; W
6 S" B5 m) T& r% Jwhile(1);1 S- Y$ L* j# v- B

& y: S9 W7 y1 T  p$ r3 O}% Q, ?$ |! ]9 @
- h$ F6 X5 b: Z
* k4 V" {9 H* ^# w" y
回复

使用道具 举报

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

使用道具 举报

本版积分规则

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

GMT+8, 2025-12-16 08:34 , Processed in 0.032608 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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