在学习C语言的时候,编写些函数的小例程时,我们大多数时候都没有去考虑该函数的可重入和不可重入性,但是在嵌入式编程中,因为涉及到中断服务或者多线程的调用,就需要考虑我们当前的定义的变量是否可以共享,如果不可以共享的情况下,我们就需要对应的设计为不可重入函数,如果可以共享,那就需要设计成可重入函数,因为如果把不可重入函数当作可重入函数来调用的话,该函数在进入中断服务或是被多个线程调用时,就会改变其变量的值,而此种改变又不是我们预先期待的改变,就可以会导致程序的意外奔溃。因此在嵌入式编程中,就需要考虑被调用的函数的属性,是可重入还是非重入。

下面我们来看看可重入函数和非重入函数所具有的特性:

可重入函数:

函数所使用的变量为私有变量或局部变量(其作用域和生命周期

仅限于函数体)

函数所使用的变量是由malloc()等函数,动态地分配内存的

函数不能返回指向静态内存的指针变量

函数用的数据来源是该函数的调用者提供

函数体内不能嵌套有非重入的函数

函数体内嵌套可重入的函数,依然还是可重入函数

非重入函数:

函数所使用的变量为全局变量或静态属性的变量

函数体内所使用的变量一般不会被轻易改变,或者只能做预期的改变

可以在函数体内通过设置禁用中断或加入互斥锁,来实现非重入的特性

下面通过几个小例程来具体分析一下函数所具有的特性,在举第一个小例程之时,先来挖个坑儿,不知道大家在学C语言的时候有没有注意过这个问题?

//exchange the value of parameteresvoid Swap_Value(uint x, uint y){uint tmp;tmp = x;x = y;y = tmp;}

首先从函数的特性上来讲,这个函数属于可重入函数,但是该函数实现不了相应交换功能,为什么呢?因为在C语言中,以传值的方式来将参数传给被调用的函数,因此被调用的函数不能改变主调函数传递过来的值,换而言之被调用函数仅仅只改变的是该变量拷贝过来的副本值,实际存储在内存里面的值并未改变,我们下面来验证一下这个例程的准确性:

#include #define uint unsigned int

void Swap_Value(uint x, uint y);

int main(void){uint a, b;a = 2;b = 3;Swap_Value(a, b);printf("a = %d, b = %d\n", a, b);return 0;}

输出的结果:

a = 2, b = 3

--------------------------------

Process exited after 0.1394 seconds with return value 0

请按任意键继续. . .

那么我们该怎么改写这个函数,才可以达到原本的意图呢?

void Swap_Value(uint *px, uint *py){uint tmp;tmp = *px;*px = *py;*py = tmp;}

既然我们没有办法直接来修改主调函数变量的值,那么我们可以通过指针变量来间接访问和改变主调函数传来的变量所在内存里面存储的值,而在调用该函数时,就需要用到取地址符&,来获取主调函数传递的参数的地址。

测试的函数如下:

#include #define uint unsigned int

void Swap_Value(uint *px, uint *py);

int main(void){uint a, b;a = 2;b = 3;Swap_Value(&a, &b);printf("a = %d, b = %d\n", a, b);return 0;}

输出结果:

a = 3, b = 2

--------------------------------

Process exited after 0.8997 seconds with return value 0

请按任意键继续. . .

接着举几个可重入函数的例子

char *Str_Name(char *name, char *sname){sprintf(sname, "%s", name);return sname;}​​​​​​

char *Str_Name(char* name){char *sname = (char*)malloc(Max_Size * sizeof(char));if(NULL != sname){sprintf(sname, "%s", name);}return sname;}

这个函数有必要再提一提,关于malloc()动态分配内存的,后面必须要进行判空操作,而且此时的判空操作将NULL放置于左边,这样的好处就是就算你忘记用"!="错用了"!"或"=",在编译时这个地方肯定会报错,从而提醒你需要修改。

下面再来举几个非重入函数的例子

char* Str_Name(char* name){static char sname[Max_Size] = {0};sprintf(sname, "%s", name);return sname;}

int a;

int func1(void){return a * 20;}

int func2(void){return func1() * 10;}

char arr[10] = {0};int index = 0;

int func(char c){if(index >= (sizeof(arr)/sizeof(arr[0]))){printf("No storage\n");return -1;}

/* ...Lock a mutex here...*/

arr[index] = c;index++;

/* ...unlock the mutex here...*/

return index;}

该代码块中,需要加入了互斥锁,这样才可以保证了该函数被安全的调用。

好了关于函数的可重入以及不可重入就介绍到这里了,真正的应用需要去实际的项目工程中去实践和验证!

c语言reentrant,Reentrant Non-reentrant Function相关推荐

  1. 【C语言】报错In function main

    C语言报错 报错 --\MinGW64\x86_64-w64-mingw32\lib\libmingw32.a(lib64_libmingw32_a-crt0_c.o) In function 'ma ...

  2. C语言常见问题(8):Refactor this function to reduce its Cognitive Complexity from 43 to the 25 allowed

    函数写得越复杂越绕,它的复杂度就越高,表面上看起来技术含量很高,在实际开发中经常会导致代码可读性差,别人来接手或学习这一块代码的时候头容易痛.身为程序员,都不大喜欢去接手别人的代码,为啥?因为怕代码写 ...

  3. Franklin C-51语言程序设计基础

    Franklin C-51语言程序设计基础 1.1 Franklin C-51数据类型 Franklin C-51编译器支持下列数据类型: 数据类型 长度 值域 bit 1 字节 0 或 1 sign ...

  4. 如何设计一门语言(一)——什么是坑(a)

    这个系列的起因是这样的,王垠写了一篇喷go的博客http://www.yinwang.org/blog-cn/2013/04/24/go-language/,里面说go已经烂到无可救药了,已经懒得说了 ...

  5. Python学习笔记(4):Python如何设置类似C语言静态函数

    介绍 模块封装时候,希望有一些函数不被外部直接调用.C语言通常采用static int function()形式以及头文件形式作为标识.而python不存在头文件,但可以通过修饰符@staticmet ...

  6. ASP.NET MVC 多语言开发简单案例

    首先,新建一个空的MVC项目,增加一个名叫Language的文件夹用于存放资源文件,如下图所示: 在Language文件夹中,增加两个资源文件,分别用于存储中文和英文,如下图所示: 如何添加资源文件? ...

  7. r语言调用python_python3调用R语言干货

    1. 安装库rpy2 1. 下载与本地对应python版本模块,pip install rpy2是安装不上的 下载地址是:http://www.lfd.uci.edu/~gohlke/pythonli ...

  8. c语言string函数的用法_C语言基础| 指针和函数

    点击蓝字关注我们 指针和函数 栈帧:当函数被调用时,系统会在stack空间上申请一块内存,用来给函数提供空间,存储形参和局部变量(定义在函数内部的变量). 当函数调用结束时,这块内存空间会被自动释放( ...

  9. mcem r语言代码_生态学数据处理常用R语言代码

    使用R来处理生态学数据越来越受到科研工作者的青睐,语义编程风格.漂亮的出图效果,能直接俘获众多用户.本文将生态学数据处理中经常会使用到的功能做个搜集整理. 本文假设读者有一些R的基础知识,对于R的编程 ...

最新文章

  1. 我的面试(四)补充1
  2. python 搭配 及目录结构
  3. 五分钟学会centos配置gitlab
  4. LeetCode175 组合两个表
  5. mysql开启慢查询
  6. Linux运行jmeter
  7. View-屏幕坐标 Content-网页(内容)坐标 mScrollX和mScrollY-屏幕坐标偏移
  8. sql between...and 用法(mysql)
  9. poj 2395 prime的递归实现
  10. HTML5微数据学习笔记
  11. c语言学习建议,学习c语言的建议
  12. 【环境配置】Collecting package metadata (current_repodata.json): failed的问题解决
  13. 路由器与交换机的区别与联系
  14. 三大条件致病菌|大肠埃希氏菌、血链球菌、李斯特菌
  15. oppo小布机器人_OPPO小布助手建立GUI+VUI协作机制,创新快应用融合能力
  16. 重装win10系统后不能上网如何解决?
  17. 傲天AC EAG误配置导致Portal推送失败案例
  18. 如何理解BRD、MRD、PRD这些名词
  19. 计算机网络体系结构-移动IP
  20. 熊市到来 扛过便是春暖花开

热门文章

  1. 射频天线设计-阻抗匹配
  2. Fresh Air(逆向思维+bfs)
  3. sharding-jdbc的使用
  4. 转发 Mac 键盘上的按键操作
  5. oracle中有关listagg函数的使用
  6. 上投摩根灵魂人物吕俊辞职
  7. Mac AppleScript实现Chrome浏览器自动化
  8. C/C++中的#if()和 #endif
  9. 惊!初中生也来卷了……
  10. 保护工控系统网络安全的关键三步