使用#ifndef #define #endif对C头文件进行最佳练习

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

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

我该如何命名#define指令中的标题? 我见过所有从BLAFOO_H__BLAFOO_H_BLAFOO_H_等。

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

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

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

我使用UUID ,这是我保证#define不与其他人发生冲突的保证。 我已经在某个地方看到它,并决定也使用它。

我的模式是这样的: ___H___

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

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

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

 #ifndef ABC_DEF_BLAFOO_H_05_30_2010 

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

与其他C风格的问题一样,只需要保持一致 。 您无法知道某人可能在将来与您的程序链接的每个库的命名空间。 为什么? 其中许多尚未编写:)

因此,它不是一个包含警卫的问题,而是一个首先命名标题的问题。

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

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

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

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

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

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

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

如果您经历了寻找唯一命名空间的麻烦,请务必使用它:)

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