使用带有#ifdef标头防护的.c文件链接.h文件

时间:2013-01-12 03:47:52

标签: c multiple-inclusions

我无法链接.h和.c文件,我也阅读了一些关于这个问题的线索,所有这些都有点模糊,但我还是无法完全掌握它的概念,而且我有很多链接问题,说我有bc和bh我将在ac 中使用,我很困惑是否包括bh ac和bc cuz bc本身需要知道bh中定义的结构,我有一些在bh中有原型的函数,在bc中定义,也使用bh中的结构,我不包括bc中的bh因为我知道bh更像是一个接口,它将使用bc中的函数。这里一个更明确的例子

b.h文件

typedef struct{
int x, y;
}myStruct;

void funct1(myStruct);
void funct2(myStruct);

b.c档案

void funct1(myStruct x)
{
    //do something
}

void funct2(myStruct y)
{
     //do something
} 

a.c文件

#include "b.h"

int main()
{
myStruct x;
  funct1(x);
  funct2(y);
return 0;
}

在cygwin中执行命令: gcc b.c a.c -g

现在令人困惑的部分,我有一个链接错误,其中当编译b.c时,它无法检测b.h中的结构和原型。我所知道的是,b.h用于链接来自a.c的b.c但是当两个.c被编译时,似乎b.c无法找到它的结构和原型,

为什么我没有在b.c中包含b.h? 答案:因为我知道,因为bh已经包含在交流中,当我再次将其包含在bc中时,我会做双重包含< ---这就是我到目前为止学到的东西知道有#ifdef但似乎它不起作用,也许我还是不知道如何使用它,如果你知道的话请随意讨论这个。

如果你有任何关于如何去做的想法,请随时告诉我一些。

有#ifdef指令,但我似乎无法知道如何做到这一点。

注意:如果有任何拼写错误的单词,请假设所有上面的代码都是完全正确的,请忽略,我只是在.h和.c之后的内容之后

4 个答案:

答案 0 :(得分:26)

您确实需要#include b.h中的b.c。在链接器接管之前,每个文件都是单独编译的,因此在a.c中包含b.h并不重要,因为b.c是自己编译的,除非你包含b.h,否则它不知道b.h的内容。

以下是#include警卫

的示例
// some_header_file.h
#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
// your code
#endif

当some_header_file.h包含在任何地方时,如果已定义SOME_HEADER_FILE_H,则将忽略#ifndef#endif之间的所有内容,这将在第一次包含在编译单元中时发生

通常的做法是在文件名后面命名#define,以确保项目的唯一性。我喜欢在其前面添加我的项目或命名空间的名称,以减少与其他代码发生冲突的风险。

注意:即使使用上面的include guard,也可以在项目中多次包含相同的头文件,它只能在同一个编译单元中包含两次。这证明如下:

// header1.h
#ifndef HEADER_H
#define HEADER_H
int test1 = 1;
#endif

// header2.h
#ifndef HEADER_H
#define HEADER_H
int test2 = 2;
#endif

现在让我们看看当我们尝试包含上述两个文件时会发生什么。在单个编译单元中:

// a.cpp
#include "header1.h"
#include "header2.h"
#include <iostream>
int main()
{
   std::cout << test1;
   std::cout << test2;
};

这会生成编译器错误,因为未定义test2 - 它在header2.h中被忽略,因为HEADER_H已经被包含的时间定义。现在,如果我们将每个标头包含在单独的编译单元中:

// a.cpp
#include "header2.h"
int getTest2()
{
   return test2;
};

// b.cpp
#include "header1.h"
#include <iostream>
int getTest2(); // forward declaration
int main()
{
   std::cout << test1;
   std::cout << getTest2();
};

编译很好并产生预期的输出(1和2),即使我们包含两个定义HEADER_H的文件。

答案 1 :(得分:3)

您需要在使用b.h中定义的结构的所有文件中包含b.h。所以你需要在两个文件中加上#include <b.h>。为避免多次加载b.h,您需要指令#ifdef。在你的情况下:

b.h

#ifndef B_H
#define B_H

typedef struct{
    int x, y;
}myStruct;

void funct1(myStruct);
void funct2(myStruct);

#endif

和b.c:

#include "b.h"

void funct1(myStruct x)
{
    //do something
}

void funct2(myStruct y)
{
     //do something
} 

答案 2 :(得分:1)

正确的编码可以包括b.c中的b.h。

这是一个应该有效的标题保护:

#ifndef B_H_INCLUDED
#define B_H_INCLUDED
//header file
#endif

将您的声明放在评论所在的位置,并包含您需要的任何位置。

EDIT 我理解它的方式是gcc首先编译b.c,因为a.c取决于b.c.但是当它首先编译b.c时,b.h 尚未被包含

答案 3 :(得分:0)

你需要在b.c中#include b.h.它不仅仅是a.c的接口,b.c也需要知道自己代码的相同定义。你在b.c中不包括b.h的原因是错误的。每个.c文件都与其他所有.c文件分开编译。当编译器使用a.c完成时,它将以b.c.重新开始。 a.c包含b.h并不重要,因为b.c没有a.c甚至存在的概念。如果在编译给定的.c文件时多次包含.h文件,则头文件防护的目的是防止.h文件被重复处理。如果没有防护,声明将被多次编译,导致现有符号的多个声明出错。