13

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

.bh 文件

typedef struct{
int x, y;
}myStruct;

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

bc 文件

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

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

交流档案

#include "b.h"

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

在cygwin中执行命令:gcc bc ac -g

现在令人困惑的部分是,我有一个链接错误,其中在编译 bc 时它无法检测到 bh 中的结构和原型因为我所知道的是 bh 用于从 ac 链接 bc 但是当编译两个 .c 时似乎bc 找不到它的结构和原型,

为什么我没有在 bc 中包含 bh? 答案:因为据我所知,bh 已经包含在 ac 中,当我再次将它包含在 bc 中时,我将进行双重包含它不会工作,也许我仍然不知道如何使用它,如果你知道请随时讨论这个。

如果您对如何进行此操作有任何想法,请随时告诉我一些。

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

注意:假设所有上述代码在语法上都是正确的,如果有任何拼写错误的单词请忽略,我只是在 .h 和 .c 之间的包含之后

4

4 回答 4

30

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

这是一个#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在文件名之后命名,以确保项目中的唯一性。我也喜欢在它前面加上我的项目或命名空间的名称,以减少与其他代码冲突的风险。

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

// 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 的文件。

于 2013-01-12T03:54:31.353 回答
3

您需要b.h在所有使用b.h. 所以你需要#include <b.h>在两个文件中都放一个。为避免b.h多次加载,您需要指令#ifdef。在你的情况下:

bh

#ifndef B_H
#define B_H

typedef struct{
    int x, y;
}myStruct;

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

#endif

和公元前:

#include "b.h"

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

void funct2(myStruct y)
{
     //do something
} 
于 2013-01-12T03:56:36.157 回答
1

正确的编码会让你在 bc 中包含 bh

这是一个应该可以工作的标头守卫:

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

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

编辑我理解的方式是gcc先编译 bc,因为 ac 依赖于 bc 但是当它先编译 bc 时, bh has not been included

于 2013-01-12T03:53:47.387 回答
0

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

于 2013-01-12T04:00:23.490 回答