【问题标题】:best-practice on C header files with #ifndef #define #endif#ifndef #define #endif 对 C 头文件的最佳实践
【发布时间】:2010-05-30 16:06:36
【问题描述】:

关于以下“模式”的最佳实践是什么?

#ifndef BLAFOO_H
#define BLAFOO_H
/* ...
 * ...
 */
#endif /* BLAFOO_H */

我应该如何命名#define 指令中的标题?从BLAFOO_H__BLAFOO_H_BLAFOO_H_ 等等,我都看过了。

【问题讨论】:

  • 仅供参考,模式被称为include guard

标签: c coding-style header


【解决方案1】:

将它们命名为BLAFOO_H(我个人使用BLAFOO_H_,其中 BLAFOO 是头文件名)。

确保您的 BLAFOO 不会与其他文件/库/等发生冲突。你正在使用,例如让您的项目和/或模块名称成为该名称的一部分。

_ 开头的标识符是为实现/编译器保留的,所以不要使用它。

【讨论】:

  • +1 表示以_ 开头的标识符保留用于实现
【解决方案2】:

我使用 UUID 保证#define 不会与其他人发生冲突。我在某处看到它并决定也使用它。

我的模式是这样的:__<filename>_H_<uuid>__

例如。 #define __TYPES_H_79057761_16D6_478A_BFBC_BBF17BD3E9B9__ 用于名为 types.h 的文件

【讨论】:

  • 如何生成 UUID?您是否在 IDE 中使用自动化工具或函数?
  • 我也认为使用 GUID 是一个好主意,但是有几个 cmets - 严格来说你不应该使用 __ 前缀,因为它是为实现保留的(尽管发生冲突的可能性很小GUID 在那里)。此外,你很有可能会发现团队中的其他人不喜欢它——至少我是这样发现的。在那种情况下,我不会推动它,因为我不记得包含保护冲突实际上导致问题的情况。
  • @Thomas - 在 Windows 上,Visual Studio(和/或 Windows SDK)提供命令行工具 uuidgen 和 GUI 工具 guidgen。我敢肯定 Unix 系统也有类似的工具。
  • @Michael:起初我自己并不喜欢这个想法,并认为它不可读/不方便使用。然而,我意识到这是拥有一个完全唯一标识符的唯一最简单的方法,并决定坚持这些简单的规则:1. 永远不要在代码中的任何地方引用它,2. 对所有头文件使用相同的 UUID,特别是 lib/project .顺便说一句 - “它是为实施而保留的”是什么意思?执行什么?由谁保留?谢谢。
  • 我不认为有太多的理由去尝试使项目中所有标头的 UUID 相同 - UUID 是免费的,只需给每个标头自己的然后忘记它。至于“保留”,详见stackoverflow.com/questions/228783/…。就像我说的那样 - 考虑到其中的 UUID,你的宏与任何东西发生冲突的可能性几乎是不可能的,但无论如何都没有理由使用双下划线,所以我会说 drop 'em。
【解决方案3】:

与其他 C 风格的问题一样,只需一致。您不可能知道将来有人可能与您的程序链接的每个库的名称空间。为什么?其中许多还没有写出来:)

因此,这不是包含守卫的问题,而是首先要命名标头的问题。

我可能会想出一些很酷的新字符串实用程序,并将标题命名为 strutil。这是一个坏主意,因为(肯定)其他人已经提出了很酷的新字符串实用程序并将标题命名为相同。

所以,我将我的命名为 post_strutils.h 并且:

#ifndef POST_STRUTILS_H
#define POST_STRUTILS_H
/* code */
#endif

我什至可以称它为post_str_utils.h 并适当地定义包含守卫,因为我知道我有一个非常常见的姓氏。有时很难找到命名空间。仅使用一个并不能保证其他人在将某些东西发布到野外之前进行了搜索。尽可能独特。

根据某人告诉他们的编译器搜索头文件的位置,它不仅仅是名称空间冲突起作用,它还包括文件名。尽量为 header 命名唯一,然后编写包含保护以匹配它。如果标头已被多次包含,有人可能想要#error,如果只是为了削减不需要的#include 指令,使用UUID 会让人感到困惑,因为它不匹配(甚至类似于) 相关标头的文件名。它还使grep/awk(或类似的)驱动的 lint 脚本更难编写。

我并不是说您应该以自己的名字命名每个库/模块,但请注意使公共头文件名唯一。与搜索引擎的快速会议将告诉您是否点击了未使用的命名空间。请让包含守卫匹配(或至少非常相似)标题。 一致性再次受到高度赞扬。从你的例子中,我希望:

int blahfoo_init(void);
double blahfoo_getval(blahfoo_t *blah);

如果您费心寻找唯一的命名空间,请务必使用它:)

【讨论】:

    【解决方案4】:

    唯一真正的要求是它不会与另一个使用相同文件名的项目冲突。对于我见过的所有项目,它通常会完全量化名称空间(或 C 文件所在的任何文件夹)以及项目名称。有时它也包括文件的创建日期。

    因此,如果您今天正在处理文件夹 DEF 中的项目 ABC,那么您可以这样做:

    #ifndef ABC_DEF_BLAFOO_H_05_30_2010
    

    这不太可能与任何事情发生冲突。

    【讨论】:

      【解决方案5】:

      只要它不太可能在其他任何地方使用,这并不重要。我通常会选择BLAFOO_H_INCLUDED

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-22
        • 1970-01-01
        • 2010-12-11
        • 2013-03-03
        • 1970-01-01
        • 2011-01-03
        • 1970-01-01
        相关资源
        最近更新 更多