一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

搜索
楼主: kenson

C 中复杂的函数声明

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

使用道具 举报

 楼主| 发表于 2015-6-18 12:44 | 显示全部楼层
xzp21st 发表于 2015-6-17 14:02
3 ?& Y. H1 G1 ^  [0 \看到这类代码就想打人
& u& X' Q$ y9 S* V: M# G# r
你想往高层去走如运行RTOS系统这类的你也要对这方面要懂得一点。
回复

使用道具 举报

 楼主| 发表于 2015-6-18 12:51 | 显示全部楼层
我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。' C& E1 X: t% f7 Z
网址:http://www.state-machine.com/9 W1 S* F' o9 G$ W9 @3 O  a) z
极力推荐!!!
回复

使用道具 举报

发表于 2015-6-18 14:11 | 显示全部楼层
kenson 发表于 2015-6-18 12:51
7 [# H  I& B! c6 {) l# I+ ~8 R% C我推荐大家看一下“层次状态机”了解一下它的思想,了解它的思想后开发什么都不难了。. J. w/ }: p' E+ s; I; t
网址:http://www.s ...

# S" d! Y1 O/ m" S, {这不是量子状态机嘛
6 \: o6 Y  y: J( w) X
回复

使用道具 举报

 楼主| 发表于 2015-6-18 14:50 | 显示全部楼层
xzp21st 发表于 2015-6-18 14:11
8 j1 @8 m5 ~$ z5 {! ^( P这不是量子状态机嘛

2 d0 X& s3 ^- u4 @$ N6 a是的!怎样对这个熟悉吗?$ G. n3 F; ?: J" Z; a
回复

使用道具 举报

 楼主| 发表于 2015-6-20 07:57 | 显示全部楼层
指向函数指针的指针# P7 X5 U; m; O; u* x( l+ Z
typedef int *(*pfun_t)(int a, int b)* f( Q) g2 W/ V' V  j# |' [
pfun_t *ppfun_t = NULL;
回复

使用道具 举报

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

) b! S% D: x% U9 i' U8 s  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
  
1
  
2
  
3
  
A) char * (*fun1)(char * p1,char * p2);
  
B) char * *fun2(char * p1,char * p2);
  
C) char * fun3(char * p1,char * p2);
  
看看上面三个表达式分别是什么意思?
' @  l, ^2 F: p2 v( Z7 S2 d7 t
C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。
; n4 ?& U& z% ^% A# EB) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。3 r3 Q* T. l1 |. Z- |8 A
A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
  
1
  
int (*)[10]  p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
  
1
  
char *  (*)(char * p1,char * p2) fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。^_^。
2.函数指针使用的例子
3 F# Q. w) I" G4 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----这是什么?
. A* ]' g3 t3 ^6 m9 W% L
  也许上面的例子过于简单,我们看看下面的例子:
  
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;
  
} 
' v# ~' k$ F# G, |2 v1 Q1 E
这是在干什么?*(int*)&p=(int)Function;表示什么意思?
5 e* ~  I* w3 ?& V# i别急,先看这行代码:
  
1
  
void (*p)();
这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。3 c& L7 `' o/ Q' Q3 n& f7 w  M
&p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。' f" b, \' M- m
(int*)&p表示将地址强制转换成指向int类型数据的指针。% i6 ]" q, g- o0 |- z- H$ j
(int)Function表示将函数的入口地址强制转换成int类型的数据。
7 E) a4 ~5 `7 y7 \3 d, G分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。
& J9 `5 o" G2 o8 a3 f# q' L, D
那么(*p) ();就是表示对函数的调用。

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

3 |  l3 K; l. a- y! B9 j7 B: V好像还是很简单是吧,上面的例子再改写改写:
  
1
  
(*(char**(*) (char **,char **))0) ( char **,char **);

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

& y0 t& r' k. B5 J8 S) W  a9 `, l  看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。
, _; r; i# ?2 C9 `其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。

2 l8 @( a7 p, z" i下面就定义一个简单的函数指针数组指针:
  
1
  
char *  (*(*pf)[3])(char * p);
6 R9 T! V4 D; O: D4 V
注意,这里的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 W' _( S% M5 \3 ?# H
! r: p/ j% X6 [
3 R. w* ]6 D# R  m2 j& G2 Y0 s
#include <REG52.H>                /* special function register declarations   */% q8 z- K: Y+ Y* V5 a  P3 Z3 N( b8 J
#include <stdlib.h>                                  /* for the intended 8051 derivative         */4 E* d  @) [" V6 y0 }
#include <string.h>) L  g- j2 N* h( z
#include <stdio.h>                /* prototype declarations for I/O functions */
% s3 s+ k2 h$ F( L% @
! d% k7 K: v- U4 t# v: E! s. N" o
/ o% l, i9 o$ N* K6 q1 x#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */) r: I# z2 G$ d9 {% f  Q, R* A
char code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */
7 ?! A! g' G/ k( F& q9 z9 o6 U/ v#endif                                   /* Stop Exection with Serial Intr.   */) n& @  f+ [4 b( C3 x
                                         /* is enabled                        */" A2 B8 x4 I& h$ V% T

. ?9 G5 ?4 ]+ r3 d; @char * fun1(char * p)
/ Q1 A/ w7 ]3 x& `6 E2 K{' D6 W! [8 a0 T+ m# {/ R5 z
printf("%s\n",p);
! i/ c# P+ B* t- A* Lreturn p;
; f& Z" W9 m5 T3 B, c' b}2 n, T; d% f8 l; C

7 t. z- c1 c9 v1 Achar * fun2(char * p)
. \  _3 Z5 k; o. x' p+ d  q{
0 N* S- p3 P) y6 `6 sprintf("%s\n",p);
! T% g! n, L4 f+ K2 w  y" D" X9 creturn p;
: ?; X9 `( l/ s" [}% l$ D5 ?3 X) N

' f0 c! m3 N1 O- Y: ^5 f0 }& ~char * fun3(char * p)
' s+ k5 i* f* S# f  r{
+ d- u7 |) S" w, P* Qprintf("%s\n",p);
7 Z5 m  i% L3 G* J; jreturn p;! b7 |" p* M2 U
}* @' a/ C' p/ s" g/ c; H, {

% b& W7 T; |2 [, |( y
& |2 O$ D+ B: V. ^; t, j* G9 W+ g! |& H. G) E
6 ]) a8 f+ Z9 p, `: |: `
4 t2 |8 D9 G, ^0 p5 T$ }$ P+ C
void main (void) {
! b& }) |) @" r7 V8 C7 V3 Q7 `/ y/ e3 P8 h2 N! T/ K* L5 W% G( z- k
char * (*pf[3])(char * p);
2 F9 G6 e1 k' p) H! n
. q$ Z0 z; Z, Q, Y% M2 D% y  V* ^# y
#ifndef MONITOR51
: k% H6 o% Y0 t& v    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */) e& M0 H3 s4 u* h
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */1 [0 Y+ R+ }9 V4 y/ F
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
0 L8 s, E& W; J    TR1   = 1;                  /* TR1:  timer 1 run                          */
/ A2 A" y7 L5 [# K. A( ^) w! K    TI    = 1;                  /* TI:   set TI to send first char of UART    */8 X: n3 j7 A+ C6 B7 _
#endif
8 [! e1 w, ~5 @' X
1 f7 E4 Q, q# X: c1 ^3 r, U0 I8 C0 M2 g
pf[0] = fun1; //可以直接用函数名
3 a$ q5 N4 y0 Opf[1] = &fun2; //可以用函数名加上取地址符8 M: X4 s2 d( F3 M$ X5 W
pf[2] = &fun3;" N8 h3 J2 a* B6 X6 y/ Y6 }
pf[0]("fun1");1 o4 I  f/ Y, n: h
pf[0]("fun2");* q" Q2 a, c7 S1 g6 O1 m$ V$ L( f
pf[0]("fun3");
; D8 @2 @) k. ^while(1);
9 z% p, y# P" f( s& R1 F% W
# y) q4 p6 T$ `( S}
  ?0 k2 k; L2 I" ^" `& A* e) |: G: W) ?0 s) P1 |3 y& [

7 q/ e& M6 A* c6 c仿真结果:9 h6 T/ d; N3 M- a
fun1/ E! m. F4 H1 d! \9 {
fun2) ~% @$ c" X: z
fun31 e6 e/ Q3 j2 q
2 e0 i& Q! D+ r3 ^* T7 R
回复

使用道具 举报

 楼主| 发表于 2015-6-21 16:05 | 显示全部楼层
本帖最后由 kenson 于 2015-6-21 16:12 编辑 5 {' m  ^& ?, H( y" y& F
3 F7 y1 s, Z0 j
void main (void) {: p# z; \" c' S! y* O" o9 c
    char * (*a[3])(char * p);: p% s5 o& s) {4 |6 T
    char * (*(*pf)[3])(char * p);
( Y+ f4 ]+ v* o    pf = a;+ Y* A/ e. C* n' l8 |
' l; E/ D- t" a8 U: q1 |
% A, R5 N' E" E4 l* [: f
#ifndef MONITOR51
; n7 I+ {% q" W4 N# Q    SCON  = 0x50;                        /* SCON: mode 1, 8-bit UART, enable rcvr      */0 c0 o8 Q, M2 {! R- y3 L$ R8 L, f
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */$ |; F6 M/ b( ?0 A: _6 D
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */$ F. T, V0 `6 \) f
    TR1   = 1;                  /* TR1:  timer 1 run                          */5 H2 q. Q4 _( I- y
    TI    = 1;                  /* TI:   set TI to send first char of UART    */" Q) P5 D9 l( |- H. v
#endif6 g% ?- w! x5 N( Y

; Q+ O4 n/ h5 r* V* b" }
  J7 P! v# `: c: y
/ r% x6 k- b0 h9 f7 D, D- v    a[0] = fun1;* Y; E+ ~3 U% u9 l
    a[1] = &fun2;( G4 q" Q) B+ _* ^1 D* K# J4 p7 S
    a[2] = &fun3;
( t# E9 ?' s9 B( ~
6 w$ @0 s7 h& |5 k    pf[0][0]("fun1");/ v; t7 D: K  }* O
    pf[0][1]("fun2");, n  Q: P0 |5 D* e' K: E
    pf[0][2]("fun3");* v. ^7 g. y4 T1 U2 Q

8 w- ~6 R/ W; A2 i& Wwhile(1);
4 c7 ]# i1 N, E) r: J2 w" @. ?( e7 `2 L
}* |$ `4 u$ ]; @# p/ D
% @" G( i+ i" i8 [1 P

# L' Q5 l  O& s, m  s
回复

使用道具 举报

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

使用道具 举报

本版积分规则

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

GMT+8, 2025-8-20 12:15 , Processed in 0.036688 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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