某一个源文件内部定义的宏、类型定义、全局变量、函数的摆放位置

📅 2026/7/16 3:18:41
某一个源文件内部定义的宏、类型定义、全局变量、函数的摆放位置
最近我在看我同事写的代码因为他内部没有定义子函数而是使用了一个非常大非常长的大函数来实现业务逻辑的但是我看了Uboot源码、linux内核源码中代码书写规范我认为这种意大利面条式代码编写方式不太好于是我将一些多次重复调用的代码提取出来写成了一个个的子函数将函数中使用的常数我就近在函数上面定义成了宏定义或者枚举类型这些我修改完一遍后就遇到了一个问题宏观上看源文件的的宏、类型定义包含enum枚举类型、全局变量、函数是交叉排布的我这样能够实现业务逻辑但是各个元素交叉着与Uboot、linux内核源码的编写习惯不同为了做到统一规范需要对宏定义、类型定义、全局变量、函数摆放在与按照Uboot和linux内核源码中一致位置的规定。1uboot、linux内核源码中对宏、类型定义、全局变量、函数摆放是怎么规划的呢答大原则类型定义、全局变量、函数定义这三者以列表的方式实现摆放首先源文件开头位置是类型定义的列表、然后是以这些类型定义的全局变量的列表最后是函数定义列表摆放。宏定义按照“最小作用域”原则摆放在调用宏值的函数上面相邻位置调用完宏甚至可以使用#undef来取消宏定义这样此行代码后面的所有代码函数都不能再访问该宏了。为什么大原则是这样的呢首先我们以列表的方式摆放类型定义、全局变量、函数定义更符合c语言设计原则与数组、结构体成员变量相邻打包的原则是一致的。其次我们使用vscode打开源文件看看大纲窗口各个元素的摆放。dm9000.c源文件的大纲窗口中也是以列表的方式将将类型定义、全局变量定义、函数定义依次摆放因为我们在写代码的时候也需要以这种方式。最后我问过AI这样摆放的好处是什么说是方便后期维护修改因为相同类型的元素都是依次排布的也就是都在同一段位置附近容易查找我想了一下的确是这样。例如写好代码后过了好长时间不看源文件中使用的类型定义、全局变量、函数定义名字都不记得了如果它们三种是交叉分部的需要好好长时间才能再次捋清楚整个源文件的业务逻辑。2那么宏定义为什么不摆放在源代码开始位置然后依次排布呢我在这里不讨论这样摆放的好处是什么无非就是便于维护。我想讨论的是宏定义摆放在使用它的函数上面按照就近原则摆放的好处。首先如果将宏定义统一摆放在源文件开始位置当我们读到这个宏定义列表的时候是不清楚被哪个函数调用相反的如果在函数附近分散的排布使用的宏定义那就比较容易查找并理解了。其次vscode的大纲列表中没有体现宏定义的列表排布暗含的意思就是希望宏定义以“最小作用域”的方式分段按需摆放。最后我的原则如果某一个宏定义被2个以上函数调用的话将这个宏定义摆在源文件开始位置对应的如果某一个宏定义只被一个函数内部调用也就是“局部宏”我的建议就是将宏摆放在离函数最近的位置。往更宽了考虑如果某一种类型定义、全局变量定义、函数定义、宏定义需要被2个以上源文件共同拥有那就需要将类型定义定义在头文件中、全局变量声明放在头文件中使用extern修饰、函数声明在头文件中声明、宏定义放在头文件中这样所有包含这个头文件的源文件就都拥有。总之先往小的范围考虑优先使用小范围作用域逐级往大的地方移动。注意以上的原则都是“义务”原则尽量遵守不是强制的。例如有些源文件中函数中间插了全局变量定义这个全局变量就遵守了“最小作用域”原则在uboot或者linux内核源码中经常看到也是允许的。知识延伸记录1函数或者变量定义的单词个数尽量保持在1个、2个、3个单词之类意思就是主谓宾的组合函数名别写单词太多尤其是不要将函数名写成一句话。如果函数定义单词超过三个可以将2个容易识别意思的单词写在一起还有一个需要注意的函数名参数列表才是真正代表函数的完整含义因此函数名中无需体现参数列表的名字。2if-else嵌套级数尽量保持在一级、二级、三级这三种情况如果嵌套级数再多代码的复杂性就太大了complex不建议这样写需要根据自己的逻辑功能优化自己的代码。将多级嵌套改成多个条件使用逻辑运算 || !的方式是一种降低代码复杂性的不错方式。if-else嵌套形成的所有组合条件我们往往并不需要全都关心有时候只需要处理我们比较在意的业务逻辑那些不可能发生或者理论上存在现实中根本碰不到的情况不用理会。3源文件中宏、类型定义、全局变量、函数的摆放位置也在一定程度上体现了“流水线思维”类型定义、全局变量、函数的摆放在开头位置类比成流水线就是先准备好模具然后制作出所需原材料、各个加工机器调试摆放顺序。