你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

3个C语言技巧

[复制链接]
gaosmile 发布时间:2020-11-28 18:22
1.指向函数的指针

指针不光能指向变量、字符串、数组,还能够指向函数。在C语言中允许将函数的入口地址赋值给指针。这样就可以通过指针来访问函数。

还可以把函数指针当成参数来传递。函数指针可以简化代码,减少修改代码时的工作量。通过接下来的讲解大家会体会到这一点的。

/*函数指针简单讲解
* T% {( |! k! I0 f1 o' k/ N+ t$ I5 C *通过指向函数的指
% H0 [( k/ D' ^ *针调用比较两个数
' D  ^4 F) j" R% a( _# Z* U4 X *大小的程序
$ ]% _3 N: _' J; k; [. o! S */
; R* l7 R1 a9 e$ S+ s! |: Q: n# P0 S& z) D8 v5 p9 e
#include <iostream>! x) B7 D9 K5 @: v+ g1 _* @- z
using namespace std;
' Z' y2 \: F, ~
+ E' m! A0 R; U2 s  N3 x/*比较函数声明*/
, `9 E  O. G8 `. U' zint max(int,int);- ^' l$ p( s0 @3 Y$ R

9 C  m: o1 Y3 {/*指向函数的指针声明(此刻指针未指向任何一个函数)*/
7 U4 _- g, `1 N3 u! e5 H4 U4 cint (*test)(int,int);
, h" A! j, g8 X" \9 c
- k/ g3 E+ e0 j0 }1 t, ^int main(int argc,char* argv[])7 J3 u  p. Z0 e! X" N
{" p! R5 S) e% Y  O# k
  int largernumber;
) U7 }! O  R& s7 _) }  s0 R2 t& E+ w9 X
/*将max函数的入口地址赋值给
- e6 z" M  `  y *函数指针test
2 w% a+ C" E6 ] */
9 Z' A( N) B2 l/ T: i7 E  test=max;
$ ]9 t* Q2 K% _7 Y- m3 c7 O0 V$ w% \" D! F9 |
/*通过指针test调用函数max实! ^9 J( d7 A% L- p
*现比较大小8 l3 ?. p+ k) z0 ~$ T- s
*/: f# |' p- D6 f6 ?8 ]- K2 d6 z
  largernumber=(*test)(1,2);, [: s$ e: ^7 }* h! m3 t
  cout<<largernumber<<endl;
( ]3 f6 I+ W3 C" ~  return 0;      
; b* s1 r2 r$ [0 w}7 `0 c; z0 }( S! c

9 W6 K0 r6 t( ^7 u; w/ Xint max(int a,int b)
( s( a5 q: a) c. \# \. n6 W' U7 h{
# x' G$ b: x- K/ `' G  R: _   return (a>b?a:b);  
4 B1 h+ ?4 G% l% w' r# N# a}
6 J+ n% `5 O# A

通过注释大家应该很容易理解,函数指针其实和变量指针、字符串指针差不多的。如果大家理解了这个小程序,那么理解起下面这个有关Nand flash的源代码就好多了。

typedef struct {3 j% d4 O, @1 v- C
    void (*nand_reset)(void);/ B- a' T5 ?) L  [* V. R. U. T
    void (*wait_idle)(void);
9 I: _  o4 t" I8 C5 ]7 T2 F    void (*nand_select_chip)(void);# n* @% O  h3 Z/ r
    void (*nand_deselect_chip)(void);3 |2 U( H6 G; i; R' b
    void (*write_cmd)(int cmd);
8 b- V; D' [) x2 i    void (*write_addr)(unsigned int addr);
- |+ T# k- O+ n7 L# g7 V" p    unsigned char (*read_data)(void);
5 c9 ^: S0 L. L) z/ e}t_nand_chip;
1 f: m1 M; l; e8 Z9 P
$ ^6 F& w. n8 e2 r+ Astatic t_nand_chip nand_chip;: }2 l3 K6 I4 e! N& C" v' A
; V: H% ^* b- |4 {" C. k0 s2 A
/* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 *// K/ F9 X' k! ~6 B. _2 U
static void nand_reset(void);6 B4 A  N4 ^$ u4 m5 {
static void wait_idle(void);  @$ m9 G- t0 T7 I5 U5 [+ X2 ]
static void nand_select_chip(void);) |- b" p, A4 N4 y- A3 _1 H2 N' j
static void nand_deselect_chip(void);
* S2 q+ Q  A5 D  M+ p) jstatic void write_cmd(int cmd);
( }3 y+ I$ i1 W9 S8 J" z: estatic void write_addr(unsigned int addr);
) e( C# ?# X: istatic unsigned char read_data(void);
7 t8 J( u- Y+ r$ l& f% B% k( t4 ^; B& ]
/* S3C2410的NAND Flash处理函数 */
: c3 ^5 G3 Q) ~static void s3c2410_nand_reset(void);
) ?1 y; F9 A! g2 h4 z% V8 cstatic void s3c2410_wait_idle(void);$ T! L- P/ D9 w# @" V7 k
static void s3c2410_nand_select_chip(void);$ C' ^5 o" N* F& ~. w
static void s3c2410_nand_deselect_chip(void);
) b( E. @+ |; \static void s3c2410_write_cmd(int cmd);2 Q' B8 X% N& U# G4 a) |& h) Y
static void s3c2410_write_addr(unsigned int addr);' ~9 u: [5 m5 }( ?! t: }' R
static unsigned char s3c2410_read_data();
2 Z* @9 B, d) Q$ R+ _2 B7 J) Q% |/ e; L( n
/* S3C2440的NAND Flash处理函数 */& n  B+ u8 S" |$ i; \: W) r
static void s3c2440_nand_reset(void);
- O" s7 {& a7 \- x7 [$ X4 l: _static void s3c2440_wait_idle(void);5 z, U$ |" C2 L; Q; u; w
static void s3c2440_nand_select_chip(void);
! [% L& h7 o8 \) [: Xstatic void s3c2440_nand_deselect_chip(void);
& q1 o3 r. m2 k* Jstatic void s3c2440_write_cmd(int cmd);0 h" ]! [9 _) F! m4 c
static void s3c2440_write_addr(unsigned int addr);0 u2 o+ S7 c3 `& t
static unsigned char s3c2440_read_data(void);
/ L+ \$ h; z+ I2 Z7 h  v  I* S: v8 s. `( ?2 H5 W9 ~6 c, W" q
8 i* t: u  }* S. \1 {7 e
/* 初始化NAND Flash */; Y- V5 R% y6 ~! f1 a* Z! l
void nand_init(void)" l' U/ ?2 v& S
{
7 u6 q! X$ b+ }/ L2 {#define TACLS   0
, y) f+ a6 r8 j#define TWRPH0  3
" W! W  J) H& D4 t2 Z8 z4 Y#define TWRPH1  05 A6 d+ T. n- c3 W5 ]
, @- O6 o, \8 X6 |0 H7 {
    /* 判断是S3C2410还是S3C2440 */: u' f1 Y# F, k- E
    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
6 I+ a$ q2 y6 z( e. O    {+ ^+ h" v) H3 V7 o" C
        nand_chip.nand_reset         = s3c2410_nand_reset;
& B: M' W5 Z# L        nand_chip.wait_idle          = s3c2410_wait_idle;
, l" l5 X' d9 N( i- R" V        nand_chip.nand_select_chip   = s3c2410_nand_select_chip;
5 I' E0 `$ w8 N% Q1 w* o: f% e        nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip;
" n/ s1 F' ^! `* C        nand_chip.write_cmd          = s3c2410_write_cmd;; C# e1 F3 q# Z4 g
        nand_chip.write_addr         = s3c2410_write_addr;
7 z( P9 v' c% ]2 H2 y8 K, f        nand_chip.read_data          = s3c2410_read_data;8 [7 ^) T$ a2 k( @5 j3 q
! Y1 l, V' c  }2 o$ @0 b
        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 */
, K: p  ?+ Z" Z/ l        s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);7 ]  h9 n, h7 s) {, [  e. Z
    }% ^3 I/ K/ Z- r+ G5 @/ A3 `/ ?
    else
6 p$ t4 H# H! x% `! P    {! D0 b5 p5 [  O4 o6 Z6 P8 H
        nand_chip.nand_reset         = s3c2440_nand_reset;' p- H" D+ F3 @% _  X
        nand_chip.wait_idle          = s3c2440_wait_idle;
: x- B6 e% O0 o4 E5 c: O        nand_chip.nand_select_chip   = s3c2440_nand_select_chip;
) P  j+ `6 U) o, U9 J        nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;5 U% u0 [# Q4 B- r; C2 ]7 S! J- B
        nand_chip.write_cmd          = s3c2440_write_cmd;( E6 W5 E6 x. V5 u; v! @
#ifdef LARGER_NAND_PAGE1 ]% R! Z: H7 G1 @6 E
        nand_chip.write_addr         = s3c2440_write_addr_lp;2 t/ U( U0 h4 e
#else
( Q( c* q5 ~& d/ H        nand_chip.write_addr         = s3c2440_write_addr;+ F* u* `1 P0 R# y% Z
#endif/ L* z( j; Q9 i3 f: m6 ?
        nand_chip.read_data          = s3c2440_read_data;
% T! Z* ^- W" l5 b
" L  P# e; R) {' u% B. E6 z        /* 设置时序 */
1 _" Z# ~0 j# J/ n6 F/ x5 T! ]- R1 B4 ?        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
* T3 Y+ J( Q& n        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
0 [: g* K% h; c  _$ e6 X        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
$ z4 P9 f% E5 }) ]0 \    }+ B  W/ v9 z1 [9 V8 V
   
( F# ]. c3 y6 w" {- U. I1 g    /* 复位NAND Flash */9 l# \( m- D, J: f
    nand_reset();/ w' ]6 \2 Q' {
}
/ b! W* h' J- l+ R9 K$ ~* f) }+ I

这段代码是用于操作Nand Flash的一段源代码。首先我们看到开始定义了一个结构体,里面放置的全是函数指针。他们等待被赋值。然后是定义了一个这种结构体的变量nand_chip。

然后是即将操作的函数声明。这些函数将会被其他文件的函数调用。因为在这些函数里一般都只有一条语句,就是调用结构体的函数指针。接着往下看,是针对两种架构的函数声明。然后在nand_init函数中对nand_chip进行赋值,这也就是我们刚刚讲过的,将函数的入口地址赋值给指针。

现在nand_chip已经被赋值了。如果我们要对Nand进行读写操作,我们只需调用nand_chip.read_data()或者nand_chip.write_cmd()等等函数。这是比较方便的一点,另一点,此代码具有很强的移植性,如果我们又用到了一种芯片,我们就不需要改变整篇代码,只需在nand_init函数中增加对新的芯片的判断,然后给nand_chip赋值即可。所以我说函数指针会使代码具有可移植性,易修改性。

如果大家想对函数指针有更深的理解建议看一下这篇博文:http://www.cnblogs.com/CBDoctor/archive/2012/10/15/2725219.html

写的超赞,博主很佩服^_^

2.C语言操作寄存器

在嵌入式开发中,常常要操作寄存器,对寄存器进行写入,读出等等操作。每个寄存器都有自己固有的地址,通过C语言访问这些地址就变得尤为重要。

#define GSTATUS1        (*(volatile unsigned int *)0x560000B0)* Y0 C* z: U8 a* y- Z* B( ~) L

在这里,我们举一个例子。这是一个状态寄存器的宏定义。首先,通过unsigned int我们能够知道,该寄存器是32位的。因为要避免程序执行过程中直接从cache中读取数据,所以用volatile进行修饰。

每次都要重新读取该地址上的值。首先(volatile unsigned int*)是一个指针,我们就假设它为p吧。它存储的地址就是后面的0x560000B0,然后取这个地址的值,也就是p,所以源代码变成了((volatile unsigned int *)0x560000B0),接下来我们就能直接赋值给GSTATUS1来改变地址0x560000B0上存储的值了。

/* NAND FLASH (see S3C2410 manual chapter 6) */
- w# o, J: N- q9 A% c2 K  o! ~typedef struct {: V% @  w9 n- b) [, F
    S3C24X0_REG32   NFCONF;
9 }& q7 A0 b5 o+ Q4 C' K3 M    S3C24X0_REG32   NFCMD;& V9 T$ n: `6 U/ U1 O0 B* r$ T
    S3C24X0_REG32   NFADDR;
4 j3 H7 V0 ^% \: r# E$ M' [  E    S3C24X0_REG32   NFDATA;
' Z. [6 E% Y: M; n7 B# l& t( M' x9 s    S3C24X0_REG32   NFSTAT;1 u. a/ c0 K8 }7 J
    S3C24X0_REG32   NFECC;. o6 I! c9 u$ e9 T+ Z0 G
} S3C2410_NAND;
. T) |6 P- i5 Q1 c
$ d8 e+ \0 |" Y" \: F4 M; X4 Astatic S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
4 m/ `4 C9 k9 K( q, h% f# l3 P: }4 m0 {% X& w0 R/ S/ Y+ O9 Y7 K5 P1 b
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;
# u! _9 m# \0 o  Q

有时候,你会看到这样一种情况的赋值。其实这和我们刚刚讲过的差不多。只不过这里是在定义了指针的同时对指针进行赋值。这里首先定义了结构体S3C2410_NAND,里面全部是32位的变量。

又定义了这种结构体类型的指针,且指向0x4e000000这个地址,也就是此刻s3c2410nand指向了一个实际存在的物理地址。s3c2410nand指针访问了NFSTAT变量,但我们要的是它的地址,而不是它地址上的值。所以用&取NFSTAT地址,这样再强制转换为unsigned char型的指针,赋给p,就可以直接通过p来给NFSTAT赋值了。

3.寄存器位操作#define GPFCON      (*(volatile unsigned long *)0x56000050)# i2 Y1 U4 T: \
GPFCON &=~ (0x1<<3);
7 A- {2 l7 i( I  n/ Z, Z3 e" VGPFCON |= (0x1<<3);
: _/ y% H# b9 d( H, J& ^$ q/ I

结合我们刚刚所讲的,首先宏定义寄存器,这样我们能够直接给它赋值。位操作中,我们要学会程序第2行中的,给目标位清0,这里是给bit3清0。第3行则是给bit3置1。


1 D* O) X; z" f, H2 T5 F0 Y9 N
赞 收藏 评论1 发布时间:2020-11-28 18:22

举报

1个回答
fei8377588 回答时间:2020-11-30 10:54:47
发错了
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版