原文:https://www.cnblogs.com/CrazyCatJack/p/6080266.html

1.指向函数的指针

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

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

/*函数指针简单讲解 *通过指向函数的指 *针调用比较两个数 *大小的程序 */

#include using namespace std;

/*比较函数声明*/int max(int,int);

/*指向函数的指针声明(此刻指针未指向任何一个函数)*/int (*test)(int,int);

int main(int argc,char* argv[]){  int largernumber;

/*将max函数的入口地址赋值给 *函数指针test */  test=max;

/*通过指针test调用函数max实 *现比较大小 */  largernumber=(*test)(1,2);  cout<endl;return 0;      }int max(int a,int b){return (a>b?a:b);  }

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

typedef struct {    void (*nand_reset)(void);    void (*wait_idle)(void);    void (*nand_select_chip)(void);    void (*nand_deselect_chip)(void);    void (*write_cmd)(int cmd);    void (*write_addr)(unsigned int addr);    unsigned char (*read_data)(void);}t_nand_chip;

static t_nand_chip nand_chip;

/* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 */static void nand_reset(void);static void wait_idle(void);static void nand_select_chip(void);static void nand_deselect_chip(void);static void write_cmd(int cmd);static void write_addr(unsigned int addr);static unsigned char read_data(void);

/* S3C2410的NAND Flash处理函数 */static void s3c2410_nand_reset(void);static void s3c2410_wait_idle(void);static void s3c2410_nand_select_chip(void);static void s3c2410_nand_deselect_chip(void);static void s3c2410_write_cmd(int cmd);static void s3c2410_write_addr(unsigned int addr);static unsigned char s3c2410_read_data();

/* S3C2440的NAND Flash处理函数 */static void s3c2440_nand_reset(void);static void s3c2440_wait_idle(void);static void s3c2440_nand_select_chip(void);static void s3c2440_nand_deselect_chip(void);static void s3c2440_write_cmd(int cmd);static void s3c2440_write_addr(unsigned int addr);static unsigned char s3c2440_read_data(void);

/* 初始化NAND Flash */void nand_init(void){#define TACLS   0#define TWRPH0  3#define TWRPH1  0

    /* 判断是S3C2410还是S3C2440 */    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))    {        nand_chip.nand_reset         = s3c2410_nand_reset;        nand_chip.wait_idle          = s3c2410_wait_idle;        nand_chip.nand_select_chip   = s3c2410_nand_select_chip;        nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip;        nand_chip.write_cmd          = s3c2410_write_cmd;        nand_chip.write_addr         = s3c2410_write_addr;        nand_chip.read_data          = s3c2410_read_data;

        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 */        s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);    }    else    {        nand_chip.nand_reset         = s3c2440_nand_reset;        nand_chip.wait_idle          = s3c2440_wait_idle;        nand_chip.nand_select_chip   = s3c2440_nand_select_chip;        nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;        nand_chip.write_cmd          = s3c2440_write_cmd;#ifdef LARGER_NAND_PAGE        nand_chip.write_addr         = s3c2440_write_addr_lp;#else        nand_chip.write_addr         = s3c2440_write_addr;#endif        nand_chip.read_data          = s3c2440_read_data;

        /* 设置时序 */        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);    }

    /* 复位NAND Flash */    nand_reset();}

这段代码是用于操作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)

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

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

/* NAND FLASH (see S3C2410 manual chapter 6) */typedef struct {    S3C24X0_REG32   NFCONF;    S3C24X0_REG32   NFCMD;    S3C24X0_REG32   NFADDR;    S3C24X0_REG32   NFDATA;    S3C24X0_REG32   NFSTAT;    S3C24X0_REG32   NFECC;} S3C2410_NAND;

static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;

volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;

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

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

3.寄存器位操作

#define GPFCON      (*(volatile unsigned long *)0x56000050)GPFCON &=~ (0x1<<3);GPFCON |= (0x1<<3);

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

免责声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

最后

以上就是本次的分享,如果觉得文章不错,转发、在看,也是我们继续更新得动力。

猜你喜欢:

C语言、嵌入式位操作精华技巧大汇总

C语言经典问题分享:函数不可返回指向栈内存的指针!

1024G 嵌入式资源大放送!包括但不限于C/C++、单片机、Linux等。在公众号聊天界面回复1024,即可免费获取!

c语言改变cmd 字体大小_嵌入式开发中常见3个的C语言技巧相关推荐

  1. uml+oopc嵌入式c语言开发精讲_嵌入式开发中更接近底层的汇编与C语言

    分享本文,介绍下更接近硬件底层的C语言与汇编,解释 CPU 如何执行代码. 高级语言与低级语言 学习编程其实就是学习与计算机交流的语言.因为计算机不理解人类语言,通过编译器把人类写的代码转成二进制代码 ...

  2. 二阶声波正演c语言程序_嵌入式开发中的三种程序构架

    关注.星标公众号,直达精彩内容 0.前言 在嵌入式软件开发,包括单片机开发中,软件架构对于开发人员是一个必须认真考虑的问题.软件架构对于系统整体的稳定性和可靠性是非常重要的,一个合适的软件架构不仅结构 ...

  3. esp32 怎么分配freertos 堆栈大小_嵌入式开发入门-从STM32CudeMX、FreeRtos、Proteu仿真开始...

    系统 嵌入式是什么呢? 嵌入式开发就是指在嵌入式操作系统下进行开发,常用的嵌入式操作系统有FreeRtos,ucos,linux,android等.与单片机开发最大的不同就是裸跑与跑系统的区别.嵌入式 ...

  4. oracle改字体大小_集成开发环境PL/SQL Developer教程:设置行号和修改字体大小

    PL/SQL Developer是一个集成开发环境,它专门针对Oracle数据库的存储程序单元的开发所用.PL/SQL开发者在开发Oracle应用程序的时候注重于开发工具简单易用,代码简洁和开发效率高 ...

  5. css grid随页面大小_前端开发中各种设置CSS间距的优点缺点及实例「实践」

    前言 如果两个或多个元素很接近,那么用户就会认为它们以某种方式属于彼此.当对多个设计元素进行分组时,用户可以根据它们之间的空间大小来决定它们之间的关系.没有间距,用户将很难浏览页面并知道哪些内容相关而 ...

  6. 计算机桌面 文字大小,怎样调整电脑字体大小_怎样调整字体大小

    2017-01-08 11:04:56 桌面空白处击右键---属性---外观 然后会看到有一项:字体大小,选项有三,正常,大字体,特大字体.根据自己需要可以调整,显示框会出现预选效果.决定后,点击确定 ...

  7. 改变默认字体大小和默认显示大小。默认开启电量百分比 。 漫游开关默认状态显示为开启,手机数据默认状态。流量节省(Data saver)默认状态

    vendor/mediatek/proprietary/packages/apps/SettingsProvider/ src/com/android/providers/settings/Datab ...

  8. 嵌入式开发中C语言编程要点简述!

    在嵌入式Linux的C语言开发中,C语言的基本编程依然是最重要的内容.除此之外,与一般的C语言编程相比,嵌入式Linux的C语言编程有以下一些要点: 1.库函数与系统调用 在进行C语言编程的时候,使用 ...

  9. 嵌入式开发中的C语言知识点

    嵌入式开发中的C语言知识点 1.关键字 2.数据类型 3.内存管理和存储架构 4.指针和数组 5.结构类型和对齐 6.预处理机制 1.关键字 几乎每一门语言中都有关键字,具有特殊功能,C语言也不例外, ...

最新文章

  1. c++中求字符串数组的min/max
  2. jQuery给输入框绑定键盘事件
  3. Web前端主要学什么?这些知识要掌握
  4. C语言九十五之实现经典的反转数组(通过指针或数组下标操作)
  5. javaee编程题_在JavaEE中使用CDI的简单面向方面的编程(AOP)
  6. linux——客户端服务器文件传输
  7. 最小公倍数一些性质定理及证明
  8. ckeditor编辑的使用方法
  9. ssma迁移助手_如何使用SQL Server迁移助手(SSMA)和SSIS将MySQL表迁移到SQL Server
  10. Ubuntu18.04 安装 nvidia2080Ti显卡驱动
  11. 深入浅出了解OCR识别票据原理(Applying OCR Technology for Receipt Recognition)
  12. 系统引导管理 之 以WinGrub 引导安装Fedora 4.0 为例,详述用WinGrub来引导Linux的安装...
  13. d3 svg path添加文本_svg演示kafka的broker和zookeeper动态交互
  14. 全国行政区划代码表(天地图)
  15. Python打造一款属于自己的翻译词典
  16. 【电脑运用及修理】6套台式组装机电脑配置清单大全(2022年618)
  17. 石墨烯 量子计算机,带石墨烯的量子计算
  18. x光安检图像检测数据集(7500多张图像,VOC标签)
  19. SharePoint2010资源库-视频库的使用
  20. 海康IVMS-8300平台国标对接

热门文章

  1. 软件工程敏捷开发01
  2. android 用webView作为编辑器 各种问题
  3. python的argparse模块
  4. android中获取时间
  5. FreeBSD系统忘记root密码
  6. Android 多级树形菜单
  7. Mono for Android布局控件属性小结
  8. 帧中继更具体配置信息
  9. html滚动选择框代码,如何使用最简单纯Css代码美化checkbox复选框、radios单选框和滑动按钮...
  10. 信息学奥赛一本通 1242:网线主管 | OpenJudge NOI 1.11 04:网线主管