[编辑]似乎有些人在没有阅读我的帖子的情况下进行评论和投票。请在评论前阅读。例如:如果您认为我反对包含多次文件,那么您就错过了我的帖子。
当一些包含文件被包含两次时,我想通过输出错误来捕获草率编程。
我将#pragma once
用于打算包含在其他包含文件中的包含文件。这很有效。
我知道我可以做一些"保护宏"实现这一目标。但有更好的方法吗?另一个#pragma或gcc编译选项?
这是一个守卫宏的样本:
#ifndef FILE_FOO_SEEN
#define FILE_FOO_SEEN
the entire file
#endif /* !FILE_FOO_SEEN */
这对我有用:
#ifdef FILE_FOO_SEEN
#error "FILE_FOO inappropriately included twice.
#endif /* FILE_FOO_SEEN */
#define FILE_FOO_SEEN
/* Active Code */
[edit]注意:我不是要问为什么有必要多次支持包含头文件。这是一个常见的案例,并且支持gcc编译指示。当我有一些我不想要包含的特定包含文件时,我要求的情况。如果有人不止一次地包含它们,那么它将是两个动作之一:1)将陷阱更改为#pragma一次,或2)更改代码以消除依赖性。
因为有一个特殊的pragma来支持多个包含,所以我认为有人可能有很好的技巧来避免这种情况。
[edit]添加我们遵循的一些与头文件使用相关的规则:
每个.c文件都有一个带有函数原型的伴随.h文件。您可以将此.h文件视为.c文件的接口。此.h文件还可能包含函数使用或返回的结构定义和枚举。此.h文件不需要包含在任何其他.h文件中,因为其他.h文件不使用函数。
我们不会为包含main()的.c文件创建伴随.h文件。
有时,结构和枚举的使用与返回或使用它们的函数无关。对于这些情况,枚举和结构将移动到独立的.h文件中。此.h文件将包含#pragma once
,因为它可以多次包含。
首选不透明结构。
记录接口的Doxygen文档包含在.h文件中。这很有效,因为.h文件包含.c文件的完整接口。
我们根据需要对这些规则进行例外处理,但在大多数情况下,我们遵守这些规则。
遵循这些规则使得编写单元测试更容易,因为完整的界面易于识别和理解。
答案 0 :(得分:2)
我认为你不应该这样做(提醒我不要使用你的标题,如果你决定继续这个计划,请。)
但是,如果您在两次包含标题时使用众所周知的防止损坏的机制开始:
<?php
// $_POST['what_to_do'] is actually this one - <input type="hidden" value="" id="what_to_do" name="what_to_do" />
if ($_POST['what_to_do'] == 'make_copy') {
$action = "copy";
} elseif ($_POST['what_to_do'] == 'save_as') {
$action = "edit";
}
然后您可以轻松地调整它以在文件 包含两次时生成错误(正如您在问题中所认识的那样):
#ifndef FILE_FOO_SEEN
#define FILE_FOO_SEEN
…the entire file…
#endif /* !FILE_FOO_SEEN */
由于#if defined(FILE_FOO_SEEN)
#error File foo.h already included
#else
#define FILE_FOO_SEEN
…the entire file…
#endif /* FILE_FOO_SEEN */
是标准C的一部分,因此它应该起作用 - 至少是为了从编译中获得诊断消息。它应该,但可能不会(过去的Solaris - 我正在看着你!),阻止编译成功。
根据您的编译器,您可能能够微调错误处理策略,但坦率地说,最好(到目前为止)只允许多次包含标题。
标题应该是独立的和幂等的。
#error
并且它可以正常工作)。 C标准要求标准标题。严格来说,#include "header.h"
并不是严格幂等的,但其他都是幂等的。它们都是自包含的,但<assert.h>
允许包含<inttypes.h>
。
你应该遵循标准的主导 - 它提供了很好的使用技巧。
我并未声明这是完整列表或无偏见的链接列表。
答案 1 :(得分:1)
tl; dr 您可能无法避免多个包含
程序的不同部分包含相同的标题是完全正常的。 #include
想要实现的目标是在使用之前已知所需的结构和功能。由于多个包含相同文件的速度减慢,因此编译和循环包含可能导致#pragma once
和#ifndef - #define - #endif
构造被发明的无限循环。您可能会读到#pragma once
已弃用且已过时但无论如何都会被使用...
类似地,有一个#import
而不是#include
仅包含该文件一次,但这是一个罕见的AFAIK,至少在C / C ++代码中。
现在让我们说我们在没有双重包含的情况下生成干净的代码,并为每个开发人员提供可能会执行此操作的警告。您现在遇到的问题是:如果不同文件中的多个类需要相同的数据结构,该怎么办?由于您只坚持使用单一包含,因此您需要知道文件的包含顺序。
A类需要来自B类的东西,但两者都需要带有结构的Header X.您将在A类之前包含B,并在A类文件中包含标题X.如果您现在更改类的依赖关系,则可能需要将标题X include移动到链顶部的另一个类。
现在想象一下这个包含许多文件的大项目,甚至更多的人独立工作。很明显,如果可能的话,没有人愿意解开依赖关系。所以你只需使用#pragma once
,每个人都很开心,这基本上就是关于它的整个故事。
#warning
并非完全与平台无关。
#error
停止编译/预处理。
第三种方式应该得到GCC和MSVC的支持:
#pragma message("double include")
#pragma message "double include"