头文件应该有#include
个吗?
我一般认为这种等级包含是不好的。说你有这个:
foo.h中:
#include <stdio.h> // we use something from this library here
struct foo { ... } foo;
的main.c
#include "foo.h"
/* use foo for something */
printf(...)
当前main.c的实现发生了变化,您不再使用foo.h,编译将中断,您必须手动添加<stdio.h>
。
对此:
foo.h中
// Warning! we depend on stdio.h
struct foo {...
的main.c
#include <stdio.h> //required for foo.h, also for other stuff
#include "foo.h"
当你停止使用foo时,删除它不会破坏任何东西,但删除stdio.h会破坏foo.h。
#include是否应该禁止使用.h文件?
答案 0 :(得分:4)
你已经概述了关于这个主题的两个主要哲学。
我自己的观点(我认为这就是人们真正拥有的所有观点)是标题应该尽可能自包含。我不想知道foo.h
的所有依赖关系,只是为了能够使用该标头。我也鄙视必须按特定顺序包含标题。
但是,foo.h
的开发人员也应该负责使其尽可能无依赖。例如,foo.h
标题应该写成没有stdio.h
的依赖,如果可能的话(使用前向声明可以帮助)。
请注意,C标准禁止标准标题包含另一个标准标题,但C ++标准不允许。因此,您可以看到从一个C ++编译器版本转移到另一个C ++编译器版本时所描述的问题例如,在MSVC中,包括用于引入<vector>
的{{1}},但在MSVC 2010中不再出现,因此之前编译的代码可能不再是因为您可能需要专门包含{{1} }}
然而,尽管C标准似乎提倡第二种哲学,但请注意它也要求没有标题依赖于另一种标题,并且您可以按任何顺序包含标题。因此,您可以充分利用这两个领域,但代价是C库实施者的复杂性。他们必须跳过一些环节才能做到这一点(特别是为了支持可以通过几个标题中引入的定义,例如<iterator>
或<iterator>
)。我想那些起草C ++标准的人决定将这种复杂性添加到模仿者不再合理(我不知道C ++库实现者在多大程度上利用了'漏洞' - 看起来MS可能会收紧这个问题,即使技术上不需要它。)
答案 1 :(得分:3)
我的一般建议是:
#include
它需要什么。#include
所需要的东西产生别的影响。#include
它不需要的东西,因为其他东西可能需要它。真正的测试是这样的:您应该能够编译包含任何单个#include
的源文件,并且除了“没有main()
”之外不会得到任何错误或警告。如果你通过了这个测试,那么你可以期待任何其他任何东西能够#include
你的文件没有问题。我写了一个名为“hcheck”的简短脚本,用来测试它:
#!/usr/bin/env bash
# hcheck: Check header file syntax (works on source files, too...)
if [ $# -eq 0 ]; then
echo "Usage: $0 <filename>"
exit 1
fi
for f in "$@" ; do
case $f in
*.c | *.cpp | *.cc | *.h | *.hh | *.hpp )
echo "#include \"$f\"" > hcheck.cc
printf "\n\033[4mChecking $f\033[0m\n"
make -s $hcheck.o
rm -f hcheck.o hcheck.cc
;;
esac
done
我确信这个脚本可以做得更好,但它应该是一个很好的起点。
如果这太多了,如果你的头文件几乎总是有相应的源文件,那么另一种技术是要求相关的头是源文件中的第一个#include
。例如:
foo.h中:
#ifndef Foo_h
#define Foo_h
/* #includes that Foo.h needs go here. */
/* Other header declarations here */
#endif
foo.c的:
#include "Foo.h"
/* other #includes that Foo.c needs go here. */
/* source code here */
这也显示了其他人提到的Foo.h中的“包含守卫”。
首先放置#include "Foo.h"
,Foo.h
必须#include
其依赖项,否则会出现编译错误。
答案 2 :(得分:2)
好吧,主要不应该首先依赖"foo.h"
来stdio
。包括两次东西没有坏处。
此外,也许foo。 h 并不真正需要stdio
。更有可能的是foo.c
(实施)需要stdio
。
长话短说,我认为每个人都应该包括他们需要的东西,并依赖include guards。
答案 3 :(得分:1)
一旦进入包含数百或数千个头文件的项目,这就变得站不住脚了。假设我有一个名为"MyCoolFunction.h"
的头文件,其中包含MyCoolFunction()
的原型,该函数将结构指针作为参数。我应该能够假设包含MyCoolFunction.h
将包含所有必要的内容,并且允许我在不查看.h文件的情况下使用该函数来查看我需要包含的内容。
答案 4 :(得分:0)
如果头文件需要特定标头,请将其添加到头文件
#ifndef HEADER_GUARD_YOUR_STYLE
#define HEADER_GUARD_YOUR_STYLE
#include <stdio.h> /* FILE */
int foo(FILE *);
#endif /* HEADER GUARD */
如果代码文件不需要标题,请不要添加
/* #include <stdio.h> */ /* removed because unneeded */
#include <stddef.h> /* NULL */
#include "header.h"
int main(void) {
foo(NULL);
return 0;
}
答案 5 :(得分:0)
为什么不#include与标题对应的* .c文件中的内容?