【问题标题】:Is it okay to use functions to stay organized in C?可以使用函数来保持 C 语言的组织性吗?
【发布时间】:2011-06-02 03:59:20
【问题描述】:

我是一个相对较新的 C 程序员,我注意到其他高级 OOP 语言的许多约定在 C 上并不完全适用。

可以使用简短的函数来保持你的代码井井有条(即使它可能只被调用一次)?例如void init_file(void) 中的 10-15 行,然后首先在 main() 中调用它。

【问题讨论】:

  • 您的 init_file 函数可能应该返回一些东西——如果它无法初始化文件怎么办?请记住,C 并没有真正的例外。

标签: c conventions


【解决方案1】:

我不得不说,这不仅没问题,而且通常受到鼓励。只是不要过度通过创建无数微小函数来分散思路。尽量确保每个函数执行一个单一的内聚,嗯... 函数,具有干净的接口(太多的参数可能暗示该函数正在执行的工作与它的调用者没有充分分离)。

此外,命名良好的函数可以用来替换原本需要的 cmets。除了提供重用之外,函数还可以(或替代地)提供一种组织代码并将其分解为更易于理解的更小的单元的方法。以这种方式使用函数非常类似于创建包和类/模块,但在更细粒度的级别上。

【讨论】:

  • 我还要添加不要随意分解函数,而是在下一个函数中继续它们。使 break 符合逻辑并尽可能少地传递变量。考虑一下它可以在哪里重复使用,即使你现在没有用处。
【解决方案2】:

是的。请。不要写长函数。写做一件事并做好的简短的。他们只能被调用一次的事实很好。一个好处是,如果你很好地命名你的函数,你可以避免编写随着时间的推移会与代码不同步的 cmets。

【讨论】:

    【解决方案3】:

    如果我可以冒昧地引用Code Complete的一些话:

    (这些原因细节已被缩写并在某些地方进行了释义,完整的解释请参见全文。)

    创建例程的正当理由

    注意原因重叠,并不打算相互独立。

    1. 降低复杂性 - 创建例程最重要的一个原因是降低程序的复杂性(隐藏细节,这样您就不需要考虑它们)。

    2. 引入一个中间的、可理解的抽象 - 将一段代码放入一个命名良好的例程中是记录其目的的最佳方式之一。

    3. 避免重复代码 - 创建例程的最常见原因。节省空间且更易于维护(只需检查和/或修改一处)。

    4. 隐藏序列 - 隐藏处理事件的顺序是个好主意。

    5. 隐藏指针操作 - 指针操作往往难以阅读且容易出错。将它们隔离到例程中会将重点转移到操作的意图上,而不是指针操作的机制上。

    6. 提高可移植性 - 使用例程隔离不可移植的功能。

    7. 简化复杂的布尔测试 - 将复杂的布尔测试放入函数中可以使代码更具可读性,因为测试的细节不碍事,描述性的函数名称总结了函数的目的测试。

    8. 提高性能 - 您可以在一处而不是多处优化代码。

    9. 要确保所有例程都很小? - 不。将代码放入例程有很多充分的理由,这个是不必要的。 (这是为了确保您注意而放入列表中的一项!)

    最后一句引自正文(第 7 章:高质量例程)

    最强大的心理障碍之一 创建有效的例程是一个 不愿创建一个简单的例程 出于一个简单的目的。构建一个 整个例程包含两个或三个 代码行可能看起来像 矫枉过正,但经验表明如何 一个好的小程序会很有帮助。

    【讨论】:

      【解决方案4】:

      如果一组语句可以被认为是一个东西 - 那么让它们成为一个函数

      【讨论】:

        【解决方案5】:

        我觉得还不错,我会推荐它!简短的易于证明正确的函数,名称经过深思熟虑,导致代码比冗长的复杂函数更具自我记录性。

        如果需要,任何值得使用的编译器都可以内联这些调用以生成高效的代码。

        【讨论】:

          【解决方案6】:

          功能对于保持井井有条是绝对必要的。您需要首先设计问题,然后根据需要将它们拆分为功能的不同功能。一段被多次使用的代码,可能需要写在一个函数中。

          我认为首先考虑您手头的问题,分解组件并尝试为每个组件编写一个函数。在编写函数时,看看是否有一些代码段在做同样的事情,然后把它分解成一个子函数,或者如果有一个子模块,那么它也是另一个函数的候选者。但在某个时候,这项破坏性的工作应该停止,这取决于你。一般来说,不要做太多太大的函数,也不要做太多太小的函数。

          在构造函数时请考虑设计具有高内聚和低耦合。

          EDIT1:

          您可能还想考虑单独的模块。例如,如果您需要为某些应用程序使用堆栈或队列。使其成为可以从其他函数中调用其函数的模块。这样,您可以通过将常用模块编程为单独存储的一组函数来节省重新编码。

          【讨论】:

          • “高内聚低耦合”是什么意思?
          • 耦合是一个模块对另一个模块的依赖程度。凝聚力是模块内功能的关系,自给自足。阅读 CouplingCohesion
          【解决方案7】:

          是的


          我遵循一些准则:

          1. DRY (aka DIE)
          2. 保持Cyclomatic Complexity
          3. 函数应该适合终端窗口

          在某些时候,这些原则中的每一个都需要分解一个函数,尽管我认为#2 可能意味着应该组合两个具有直线代码的函数。进行所谓的方法提取比实际将函数拆分为上半部分和下半部分更常见,因为通常的原因是提取要多次调用的公共代码。

          #1 作为决策辅助工具非常有用。就像我说的一样,“永远不要复制代码”。

          #2 给了你一个很好的理由来分解一个函数,即使没有重复的代码。如果决策逻辑超过某个复杂度阈值,我们会将其分解为更多功能,从而减少决策。

          【讨论】:

            【解决方案8】:

            无论使用何种语言,将代码重构为函数确实是一种很好的做法。即使您的代码很短,它也会使其更具可读性。 如果你的函数很短,你可以考虑内联它。

            IBM Publib article on inlining

            【讨论】:

              猜你喜欢
              • 2014-12-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-12-13
              • 2021-01-26
              • 2020-10-14
              • 2016-09-28
              • 2010-09-17
              相关资源
              最近更新 更多