“包括”是什么意思?预处理器语句#include file
复制内容file
并用这些内容替换语句。不管发生这种情况
如果“包含”是指“这些文件中的语句和符号将被多次解析,从而导致警告和错误”,那么不,包含防护将阻止这种情况。
如果“包含”是指“编译器的某些部分将读取这些文件的某些部分”,那么是的,它们将被包含多次。由于包含保护,预处理器将读取文件的第二个包含并用空行替换它,这会产生很小的开销(文件已经在内存中)。现代编译器(GCC,不确定其他编译器)可能会被优化以避免这种情况,但是请注意,该文件在第一遍包含保护,并简单地丢弃未来的包含,消除开销 - 不要担心这里的速度,清晰度和模块化更为重要。当然,编译是一个耗时的过程,但#include
您最不必担心。
为了更好地理解包含守卫,请考虑以下代码示例:
#ifndef INCLUDE_GUARD
#define INCLUDE_GUARD
// Define to 1 in first block
#define GUARDED 1
#endif
#ifndef INCLUDE_GUARD
#define INCLUDE_GUARD
// Redefine to 2 in second block
#define GUARDED 2
#endif
在(第一次)预处理之后,将GUARDED
定义什么?如果确实定义了它们的参数,则预处理器语句#ifndef
或其等效语句#if !defined()
将返回。false
因此,我们可以得出结论,第二个#ifndef
将返回 false,因此在预处理器的第一次传递之后,只有 GUARDED 的第一个定义将保留。程序中剩余的任何实例GUARDED
将在下一次通过时被 1 替换。
在您的示例中,您有一些稍微(但不是很多)更复杂的东西。展开 ExampleClient.c 中的所有#include
语句将得到以下源:(注意:我缩进了它,但这不是标题的正常样式,预处理器不会这样做。我只是想让它更具可读性)
/* ExampleClient.c */
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include <stdio.h>
#ifndef STDLIB_H
#define STDLIB_H
#define NULL 0 //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
//#include "foo.h"
#ifndef FOO_H
#define FOO_H
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
void foo(void);
#endif
//#include "bar.h"
#ifndef BAR_H
#define BAR_H
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
void bar(void);
#endif
void main(int argc, char *argv[]) {
foo();
MPI_Func();
bar();
exit(0); // Added missing semicolon
}
浏览该代码并注意何时执行各种定义。结果是:
#define STDLIB_H
int abs (int number); //etc.
#define STDLIB_H
#define NULL 0 //etc.
#define MPI_H
void MPI_Func(void);
#define FOO_H
void foo(void);
#define BAR_H
void bar(void);
关于您对其他批评/指针的请求,为什么您在所有标题中都#include stdlib.h 和 mpi.h?我知道这是一个精简的例子,但一般来说,头文件应该只包含声明其内容所必需的文件。如果您使用 stdlib 中的函数或在 foo.c 或 bar.c 中调用 MPI_func(),但函数声明很简单void foo(void)
,则不应将这些文件包含在头函数中。例如,考虑以下模块:
富.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
富.c:
#include <stdlib.h> // Defines type size_t
#include "mpi.h" // Declares function MPI_func()
#include "foo.h" // Include self so type definitions and function declarations
// in foo.h are available to all functions in foo.c
void foo(void);
size_t length;
char msg[] = "Message";
MPI_func(msg, length);
}
在这个例子中,实现foo()
需要来自 stdlib 和 mpi 的东西,但定义不需要。如果 foo() 返回或需要一个size_t
值(stdlib 中的 typedef'ed),您需要在 .h 文件中 #include stdlib。