在头文件或源文件中记录函数是否更好?


86

在区分“源”文件和“头文件”(主要是C和C ++)的语言中,最好在头文件中记录函数:

(从CCAN窃取

/**
 * time_now - return the current time
 *
 * Example:
 *  printf("Now is %lu seconds since epoch\n", (long)time_now().tv_sec);
 */
struct timeval time_now(void);

或在源文件中?

(从PostgreSQL窃取)

/*
 * Convert a UTF-8 character to a Unicode code point.
 * This is a one-character version of pg_utf2wchar_with_len.
 *
 * No error checks here, c must point to a long-enough string.
 */
pg_wchar
utf8_to_unicode(const unsigned char *c)
{
...

请注意,某些内容仅在标头中定义,例如结构,宏和static inline函数。我只是在谈论在头文件中声明并在源文件中定义的内容。

这是我能想到的一些论点。我倾向于在源文件中进行文档记录,因此我的“ Pro-header”参数可能有些弱。

专业头:

  • 用户不需要源代码即可查看文档。
    • 来源可能不方便,甚至无法获取。
    • 这使接口和实现进一步分开。

原始资料:

  • 它使标题大大缩短,使读者可以从整体上鸟瞰模块。
  • 它将功能的文档与其实现配对,从而更容易看出该功能是否按其要求执行。

在回答时,请警惕基于什么工具和“现代IDE”可以做什么的争论。例子:

  • 专业标题:代码折叠可通过隐藏注释来帮助使注释的标题更易于浏览。
  • Pro-source:cscopeFind this global definition功能将您带到源文件(定义所在的位置),而不是头文件(声明所在的位置)。

我并不是说不要提出这样的论据,但要记住,并不是每个人都对使用的工具感到满意。


相同的问题可能适用于Pascal / Delphi,在这里我们没有源文件和头文件,但有接口和实现部分。
Jan Doggen

Answers:


96

我的观点...

  • 在头文件中记录如何使用该函数,或更准确地说,在声明附近。

  • 在源文件中(或更准确地说,接近定义)记录功能的工作方式(如果从代码中看不到)。

对于标题中的鸟瞰图,您不一定需要关闭文档-您可以一次记录一组声明。

从广义上讲,调用者应该对错误和异常感兴趣(如果仅是错误和异常,则它们可以在通过抽象层传播时进行翻译),因此应在相关声明的附近进行记录。


13
+1-即在标题中记录接口。来源中如何和为什么的血腥细节。
quick_now 2011年

2
对于没有可用资源的库标题,可以添加前后条件等,以帮助进行测试。加上合理的O(n)性能,因此图书馆用户可以明智地选择。
Patrick Hughes

自然地,有时声明和定义是相同的。
Deduplicator

@Deduplicator-当即使在特殊情况下相同的规则仍然可以得出正确的结果时,为什么还要在每个特殊情况下回显这些规则?当然,重复数据删除器不应该那样做吗?
Steve314 '18

1
@Deduplicator-当然,如果不遵循您的建议,这是一个过高的推论依据,但我坚持使用。
Steve314 '18

34

如果您要使用Doxygen之类的工具(在第一个示例中请注意,由于它以开头,所以它看起来确实像是Doxygen注释/**),但这并不重要-Doxygen将浏览您的标头和源文件并查找所有注释以生成文档。

但是,我更倾向于将文档注释放在声明所在的标头中。您的客户将处理与软件接口的标头,标头就是它们将包含在其自己的源文件中的位置,这就是他们首先要查看您的API外观的地方。

例如,如果您查看大多数Linux库,则Linux软件包管理系统通常具有仅包含该库的二进制文件的软件包(对于具有需要该库的程序的“普通”用户),而您具有一个“ dev”软件包包含库的头。源代码通常不直接在包装中提供。如果您必须在某个地方获取库的源代码以获取API文档,那将非常麻烦。


2
+1-一个证明,即使您使用Doxygen,也不意味着您永远不会直接从源中读取内容。Doxygen注释有时甚至可以用作grep的标准模式,如果找到的注释接近它描述的代码,这将很方便。
Steve314 2011年

1
@ Steve314当然,我并不是说您永远不想看某些库的源代码-但这不是您寻找API的外观和使用方法的第一站。
杰斯珀

我还主张将与API相关的所有内容都保留在标头中(或至少保留在标头或源中),因为这样做可以避免在一个地方而不是另一个地方更新文档时可能出现的不一致性。
jopasserat 2014年

12

我们(大约25年前)通过创建可以在源文件中使用并由awk脚本扫描的#define(例如,解析为<nothing>的public,private等)解决了此问题。 !)自动生成.h文件。这意味着所有注释都驻留在源代码中,并在适当时被复制到生成的.h文件中。我知道这很老派,但是大大简化了这种内联文档。


1
嗯,我知道这种风格的东西可能有用,但是从我的角度来看,我总是觉得这种文档

1
用唐纳德·拉姆斯菲尔德(唐纳德·拉姆斯菲尔德,我喜欢的男人)来解释一下:“您使用自己拥有的工具进行编程,而不是使用自己希望拥有的工具进行编程。” 在过去的40多年中,我使用过的每种语言至少都有一个主要的疣(如果不是更多的话)。我们的解决方案a)可行,b)使用了当时存在的工具,c)让我们花时间将可能产生收入的代码发布出去。
彼得·罗威尔

即使我可能不会选择它,它也是一种处理标头中注释的有趣方法。生成的标头是否在版本控制中?还是这个发布可再分发源的过程?(但未由开发人员使用)
ideaman42

哦,我已经看到了同样的模式在最近的一个项目中≥2000年开始,他们是如此骄傲的聪明发明的...
5gon12eder

3
在我们的案例中,我们没有将任何生成的文件保留在版本控制下,因为它们可以轻松,直接地(重新)从跟踪的文件中导出。
彼得·罗威尔

9

假设这是较大项目中的代码(开发人员经常在源代码和标头之间移动),并且提供的不是库/中间件,而其他人可能无法访问源代码,那么我发现这可行最好...

  • 标头:
    仅当需要时,简短的1-2行注释。
    有时,在一组相关功能上方的注释也很有帮助。
  • 来源:
    函数正上方的API文档(纯文本或doxygen,如果您愿意)
  • 保留实现细节,仅与开发人员修改函数主体中的代码有关。

这样做的主要原因是使注释与代码保持接近,我注意到标头中的文档往往与代码更改不同步(当然不应该这样做,但是在我们的项目中确实如此)至少)。开发人员也可以在进行某些更改时在功能顶部添加文档,即使其他地方有标头文档。导致重复或有用的信息仅出现在文档字符串之一中。

当然,您可以选择一个约定并确保所有开发人员都遵循,我刚刚发现该约定最自然,维护起来也就麻烦最少。


最后,对于大型项目- 当您知道标题可能导致100或1000的文件在其他人更新版本控制时重新编译时,倾向于不要对标题进行小更正-也会减慢二等分错误。


5

以我的观点(相当有限且有偏见),我是专业的源代码思维方式。当我用C ++进行零碎工作时,通常会编辑一次头文件,然后再也不会真正回头看它。

当我将文档放在源文件中时,在编辑或阅读代码时总是会看到它。我想这是习惯。

但这就是我...


1
如果您拥有的只是一个编译的库和头文件,则不能很好地工作。在这种情况下,标题中的更多信息是一件好事,因为它是您唯一的接口文档。
quick_now 2011年

您可以使用doxygen生成文档-它也从.c文件中获取。因此,您可以使用已编译的库轻松分发文档。但是问题出在IDE上,它可以在使用函数的同时解析头文件并为您提供文档...但是也许可以解决一些部署脚本,该脚本会将函数注释frm .c复制到.h ...
Vit Bernatik

5

注释不是文档。函数的文档通常为2K文本,可能带有图表-例如,请参阅Windows SDK中函数的文档。即使您的文档注释允许这种情况,您也将使包含注释的代码不可读。如果要生成文档,请使用文字处理器。


更新,这几天记录(使用Qt Creator之类的东西)来记录doxygen(或克隆)的方式要容易得多,例如,在qtc中,您只需在评论前敲击几次/键,然后再输入一半工作已为您完成。由于这样的事情,我怀疑人们会跳到文字处理器来记录他们的代码。理所当然,我曾经在2005年这样做,但是现在我再也不会这样做了。现在甚至使用html编辑器似乎也很陈旧。
osirisgothra 2015年

@osirisgothra Doxygen-“文档”可能很容易做到,并且肯定会产生许多快速编写的LOC,但是在大多数情况下,所产生的“文档”的价值仍然存在争议。Doxygen注释既不是好的文档(几乎所有关键细节都被遗漏了),也不是好的注释(它们倾向于重复签名中已经显而易见的内容)。我认为nbt的说法是正确的,最好不要将真实文档与代码混合使用,因为这不利于代码的可读性。无论如何它都将不同步,这没有灵丹妙药。
cmaster

4

如果您的源代码的涉众(例如,一个小型库)由“用户”(将在不参与其实现的情况下使用该库的功能的同级开发人员)和“开发人员”(您和将要实现该库的其他开发人员)组成,然后将“用户信息”放在标题中,并将“实施说明”放在源代码中。

关于不要更改头文件超出绝对必要的愿望-我想如果您的库不是“疯狂的变化”,那么“接口”和“功能性”将不会有太大变化,并且两者都不会标头注释的更改过于频繁。另一方面,源代码注释将必须与源代码保持同步(“新鲜”)。


0

使用doxygen的全部目的是您生成文档并使其可在其他地方访问。现在,标头中的所有文档都只是垃圾,这使得快速发现所需的函子声明以及其重载更加困难。最多只能有一条内衬评论,应该放在那儿,但这甚至是不好的做法。如果您更改源文件中的文档,则会导致重新编译该源文件并重新链接。但是,如果您将文档放在标题中,则您实际上根本不想更改其中的任何内容,因为它将触发项目重建的重要部分。


1
在先前的7个答案中,这似乎并没有提供任何实质性的要点和解释
gna

1
来自前面7个问题的@gnat答案中只有一个赞成针对标头的代码。那是一个完全不同的论点。
斯拉瓦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.