【问题标题】:Should the called function always check the array size in C? [closed]被调用函数是否应该始终检查 C 中的数组大小? [关闭]
【发布时间】:2016-04-21 07:14:51
【问题描述】:

这是一个关于编程风格的问题,而不是关于技术性的问题: 我的 C 函数是否应该总是需要一个数组长度的参数,尽管该函数不依赖于它?

所以要么喜欢这个void foo(int* a, int size) 要么喜欢void foo(int* a)

例如当函数只操作数组的前 128 位时,该函数是否需要数组长度并且首先检查数组的长度是否正确,或者我应该相信调用者他遵循文档并且只使用数组的大小合适吗?

我是 C 新手,所以我担心可能会出现缓冲区溢出。为什么一个比另一个更好的技术推理会很棒。谢谢!

【问题讨论】:

  • 不是强制性的,但如果你这样做,你的功能将更加模块化
  • 永远不要盲目相信程序员会做他们应该做的事情,所以是的;您应该始终在此类函数中添加长度。
  • 以C库中的函数为例。他们提供了两种方法(例如strcmpvs.strncmp)。一般来说,C 的哲学是“如果检查程序员知道他在做什么是有代价的,假设他是。”和“让程序员决定”。
  • C 是否像 C++ 一样使用 size_t?如果是这样,您应该将其用于第二个参数,而不是 int
  • @JDługosz size_t 起源于 C,正如在 C++ 中通过 C 标头 <cstddef> 访问它的事实所表明的那样,所以是的。然而,我怀疑它在 C 库中的使用与在 C++ 库中的强制/一致。不过,这是一个很好的做法!

标签: c arrays coding-style


【解决方案1】:

我的规则是区分接口点和内部功能。接口函数需要偏执且健壮,但内部函数可以假设调用者知道他们在做什么,并且可以选择效率而不是健壮性。

【讨论】:

    【解决方案2】:

    一般规则应该是尽快发现错误。您可以在编译时、链接时或运行时捕获错误,或者永远不会被捕获并具有未定义的行为。

    由于您可以检查大小并产生运行时错误,我会说如果您的函数的用户传递了一个较小的数组,那么最好不要有未定义的行为。

    当然,有时速度更重要,如果不需要额外的速度,那么您必须传达您的用户将阅读文档。这就是许多标准库函数的编写方式。但这应该是您程序中的边缘情况。通常更喜欢捕获错误,这样您的代码中的错误就会更少。

    【讨论】:

    • “一般规则应该是让错误尽快被发现。” — 我很惊讶在 C 语言中看到 this线。似乎与 C 设计理念不太协调。
    • @tuple_cat 一开始问题有一个 C++ 标签:)
    • @tuple_cat “似乎与 C 设计理念不太相符。” - 我很想听听为什么。我不知道 C 在这方面是具体的。
    【解决方案3】:

    好问题,因为在盲目使用编程风格/方法之前,您正试图了解其背后的意图。

    让我告诉你我的观点。如果符合以下条件,则代码被认为是健康的。

    • 如果您能够阅读和理解代码,而无需 cmets。
    • 如果您的代码对于未来的维护工程师来说很容易维护,并且没有太大的困难。
    • 如果您能够为原始代码添加扩展,而无需大幅更改原始代码
    • 如果您的代码已关闭/不影响输入集中的修改,即您的代码解决了同一用例的所有不同变体。请参考Open/Closed principle

    在函数签名中包含长度的概念落在上面的前 2 个要点上。

    作为功能/逻辑的作者,您确切地知道您将要实现什么,因此您不想增加长度。但是,想想情况,一段时间后出现了一个错误,您不再在项目中,而其他人正在接管维护的角色。工程师需要付出相当大的努力才能理解您编写的内容并执行修复。

    虽然有些人认为,他们可以编写 cmets/拥有低级文档等,但这并不总是一个可行的解决方案。正确的方法是遵循使代码审查直观的编程风格,并帮助未来的开发人员轻松地为项目做出贡献。

    总而言之,不,提供长度不是强制性的,但始终建议遵循良好的编码指南以培养良好的生态系统。

    如果您想为任何开源项目做出贡献,那么您应该肯定地接受这个概念 :-)

    祝你好运!

    【讨论】:

    • “在函数签名中包含长度的概念,落在上面的前 2 个要点上。” - 强烈反对。我注意到你没有解释为什么,只是说出了一堆没有真正说明什么的陈词滥调。那么,为什么你认为包含大小 (A) 会让人“无法阅读和理解代码”,而 (B) 会让人“毫无困难”地维护代码?
    • 嗯,添加长度的目的是为了捕捉某些错误场景,同时也是为了防止某些错误场景。到时候,我想回答那些,我看到那些已经回答了。因此,我不想引用同一点,而只是想给出健康编码的其他观点。
    • 假设作者没有明确指定长度并且函数内部的代码使用幻数 128 / MACRO 并假设调用者和被调用者是不同组件的一部分,维护方式不同。那么对于未来的开发人员来说,他可能会对神奇的数字 128 持怀疑态度。这就是可维护性部分的用武之地。
    【解决方案4】:

    简短回答: 是的你应该。 :D 长答案: 由于您的数组实际上是一个内存指针,因此您无法轻松获得它的实际大小。因此,如果您的函数应该修改数组数据,明智的做法是检查它是否可以在不覆盖未分配给数组的内存的情况下真正做到这一点。 在将数据写入指针之前检查内存限制通常是一个好习惯! ;)

    【讨论】:

    • [redeleted comment] 确实,只有一个指针,它不是“不容易”:你根本无法知道相应分配的大小。 (有人可能会说您可以利用您的操作系统跟踪此信息的方式,但这充其量是一种危险的黑客攻击)
    【解决方案5】:

    我会这么说,正如 Souvrav 所说,这不是强制性的,这意味着如果您 100% 确定长度“正确”,则可以跳过检查,但即使您 120% 也不建议这样做确保不会溢出。此外,添加此检查使该函数可用于您不确定长度的情况,因此即使您认为不需要它,最好直接添加它,当您的代码增长时它可能会派上用场。

    【讨论】:

      【解决方案6】:

      既然是 C,你应该“相信程序员”。

      无法确保size 参数是数组的实际长度。它可以是任意数字。那么为什么要麻烦(并弄乱界面)(并减慢程序的速度)?

      【讨论】:

      • 我并不反对你,但汽车、航空航天和国防等一些行业坚持使用 C 而不是“信任”C++
      • C 可以是安全的。如果您不想这样做,则不必使其安全,但我们不要暗示它本质上是不(能够)安全的。一个好的程序员可以做到这一点。我认为 C++ 很棒,但我也认为您在这里是从自己的偏见中推断出来的。
      • C 在某些情况下可能是安全的,但在这种特定情况 中,无法确保“length”参数是数组的实际长度。它可以是任意数字。绝对 no 方法可以确保数组参数具有特定长度。我不明白这不是天生不安全的。
      • 对,在这种特定情况下。它可以通过例如使用包含指针和大小值的struct 来使其安全。你的结束语比这更笼统,这就是我的回应。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-31
      • 2021-12-24
      • 2016-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多