全局变量直接访问和“函数调用+函数参数地址传参”的关系

发布时间:2026/7/14 15:36:36

全局变量直接访问和“函数调用+函数参数地址传参”的关系 我以前自己写的文章以及搜索“大量使用全局变量的坏处”等文章都提到尽量少直接访问全局变量而是使用函数传参的方式只在首函数内部一次接收了全局变量的地址数值给子函数然后这个子函数内部利用参数栈变量解引用方式对全局变量本体进行读写访问。我认为都没有写个点子上我以前认为这样不是很麻烦吗既分配了新的栈变量作为参数占用了内存空间子函数内部最终不是还是对全局变量的本体进行读写访问吗无论是局变量直接访问还是“函数调用函数参数地址传参”方式都最终是对全局变量的读写访问该怎么写写几次写什么读几次读什么本质上是一样的是由业务逻辑决定的何必多此一举呢为什么不直接访问呢我现在的答案是直接访问全局变量的访问权限太宽了会存在形成“竞争”的风险也就是如果把全局变量看做资源的话这个资源是共享的什么函数都可以去写它读它如果略微不注意顺序的话可能会出现某一个函数写入有效数值还没来的及读它就被另外一个函数写另外一个数值了存在“资源访问错误”的风险。要想杜绝“竞争”的形成需要做的就是人为的强制规定对全局变量本体的续写顺序什么时候对全局变量写有效数值后面什么时候读它不能还没写入有效数值就开始读它等等这样就人为强制规定了对全局变量的“一条线式”访问。那么怎么实现这种人为强制规定了对全局变量的“一条线式”访问。全局变量直接访问的弊端权限太宽了任何函数都可以在内部随时对全局变量进行读写访问我们显然不能使用。要想实现这种人为强制规定了对全局变量的“一条线式”访问降低竞争的风险唯一的办法就是使用子函数调用函数参数地址传参的方式。子函数调用有个特点就是“线性的”一个子函数首先被调用它内部实现了对全局变量的读写访问然后最后调用另外一个孙函数并将全局变量的地址值传递给孙函数这样一级一级下去。父函数被调用参数接收一次全局变量地址值---》父函数内部使用箭头运算实现的完成了一部分全局变量的写操作---》最后调用子函数接收父函数的参数值参数值是在栈空间上内部是全局变量的地址---》子函数内部通过箭头运算符完成对全局变量的读操作---》最后调用孙函数接收子函数的参数值...依次函数调用上一级参数传参直到最后。我们看一个实例USB设备的初始化过程。整个过程如上所示值得注意的是每一个子函数都有栈空间要么是参数要么就是函数内部定义的临时栈变量或者另外一个全局变量本身在函数调用过程中这些变量都不会被释放掉一直存在。这样一级一级子函数调用下去下一层子函数的参数传递的是上一级函数的内部数值或者参数实际地址值本身而非直接使用全局变量只有父函数被调用时使用了一次全局变量地址传参。值得注意的是函数的参数很多情况下是结构体指针变量也就是地址值这个数值是不变的使用箭头运算符“-”就可以实现对真正变量也就是全局变量的访问。但是因为子函数调用是一级一级的所以每一个子函数都是串行访问全局变量的同时只可能有一个子函数在真正访问全局变量因此大大降低了全局变量被同时访问的风险。子函数调用地址参数传参就是将全局变量访问强制规定成了线性顺序访问大大降低了全局变量同时访问形成“竞争”的风险。总结1全局变量直接调用和“子函数调用地址传参”在本质上都是对全局变量的读写访问宏观上看是没区别的。2全局变量的访问权限太宽了容易形成“竞态”“子函数调用地址传参”可以人为的规定对全局变量本身读写访问顺序大大降低“竞态”的形成。3全局变量直接访问和“子函数调用地址传参”两种方式是并存的不是二选一的两者并不冲突有时候直接使用全局变量更好有时候使用“子函数调用地址传参”更合理。4结构体变量整体无法直接访问也不是绝对的直接整体访问用的很少的特点决定了对结构体内部成员访问更适合使用“子函数调用地址传参”。5“子函数调用地址传参”方式的前提是定义了一个子函数子函数要想实现对上一级父函数内部的变量或者参数变量的读写访问这些变量或者参数是在父函数的栈变量的适用范围只在父函数内部进入某个子函数内部后是无法直接使用的只能在子函数调用的时候使用传参方式访问没有其他办法不能像全局变量一样直接调用。6“子函数调用地址传参”的连续性隐藏着父函数内部变量访问的权限访问。“子函数调用地址传参”的好处除了人为规定了对全局变量本身的线性顺序访问减少了“竞争”之外还有一个隐藏特点就是子函数参数传递数值只能直接来自调用它的父函数不考虑全局变量作为参数情况这样子函数只能读写调用它的父函数的变量而无法访问其他函数内部的变量减少了代码之间耦合性降低了代码编写难度各自子函数只需也只能处理和调用它的父函数之间的变量做到了“各门各扫门前雪”。例如函数A调用函数B函数B调用函数C,函数B中的变量只能由它自己读写访问或者函数C使用地址传参方式对B的变量进行读写访问而无法传递更上一级的函数A中变量同理函数A中的变量只能是函数A自己内部代码进行读写访问以及函数B通过地址传参方式进行读写访问。有点像一条锁链每一环只能与前面那个环进行相连而无法与其他环相连。7“子函数调用地址传参”的前提是子函数的定义一个子函数往往实现一个特定的功能“子函数调用地址传参”的方式隐藏了“子函数”内部代码一定程度上降低了代码阅读难度。另外子函数内部编写的时候往往不需要考虑传参传递值是多少直接假设参数变量已经被赋值但是赋值的具体数值变量是未知的完成函数体代码编写。今天主要讲解了C语言中“竞态”的形成原因如何使用“子函数调用地址传参”方式解决“竞态”“子函数调用地址传参”的线性关系。

相关新闻