Связывание файлов.h с.c с помощью защиты заголовков #ifdef

У меня проблемы с связыванием файлов.h и.c, я также прочитал некоторые темы, касающиеся этой проблемы, и все они немного расплывчаты, и все же я не могу полностью понять концепцию этого, и у меня много проблем с связыванием Скажем, у меня есть bc и bh, которые я буду использовать в ac, и я запутался, нужно ли включать bh как ac, так и bc, потому что сама bc должна знать структуру, определенную в bh, у меня есть некоторая функция, которая имеет свой прототип в bh и определена в bc, которые также используют структуру в bh, я не включаю bh в bc, потому что то, что я знаю, 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
} 

файл ac

#include "b.h"

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

Выполнил команду в cygwin: gcc bc ac -g

Теперь запутанная часть, у меня есть ошибка компоновки: когда компилируется bc, он не может обнаружить структуру и прототипы в bh, потому что все, что я знаю, это то, что bh используется для связывания bc из ac, но когда оба.c компилируются, кажется, что до н.э. не может найти его структуру и прототипы,

Почему я не включил чч в БК? Ответ: Потому что то, что я знаю, bh уже включено в ac, и когда я снова включу его в bc, я буду делать двойные включения <--- это то, что я изучаю до сих пор, и я знаю, что есть #ifdef, но кажется это не сработает, может быть, я все еще не знаю, как его использовать, если вы знаете, пожалуйста, не стесняйтесь обсуждать это.

Если у вас есть идеи о том, как это сделать, не стесняйтесь рассказать мне немного.

есть директива #ifdef, но я не могу представить, как это сделать.

ПРИМЕЧАНИЕ: ПРИМЕРЯЙТЕ, ЧТО ВСЕ ВЫШЕ КОДЫ СИНТАКТИЧЕСКИ ПРАВИЛЬНО, если есть какие-либо слова с ошибками, пожалуйста, игнорируйте, я только после включений между.h и.c

4 ответа

Решение

Вам действительно нужно #include b.h в b.c, Каждый файл компилируется отдельно перед тем, как компоновщик вступает во владение, поэтому не имеет значения, что вы включили bh в ac, потому что bc компилируется сам по себе и не имеет представления о содержимом bh, если вы его не включите.

Вот пример #include охрана

// some_header_file.h
#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
// your code
#endif

Когда some_header_file.h включен где-либо, все между #ifndef и #endif будет игнорироваться, если был определен SOME_HEADER_FILE_H, что произойдет при первом включении в модуль компиляции.

Это обычная практика, чтобы назвать #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.

Вы должны включить b.h во всех файлах, которые используют структуры, которые определены в b.h, Так что вам нужно положить #include <b.h> в обоих файлах. Чтобы избежать этого b.h загружается несколько раз, вам нужны директивы #ifdef, В твоем случае:

ЬН

#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
} 

Правильное кодирование будет включать BH в BC

Вот защита заголовка, которая должна работать:

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

Поместите свои декларации там, где есть комментарий, и включайте их везде, где это необходимо.

РЕДАКТИРОВАТЬ То, как я понимаю, это то, что gcc сначала компилируется bc, потому что ac зависит от bc. Но когда компилируется сначала bc, bh еще не включается.

Вам нужно #include bh in bc Это не просто интерфейс для ac, bc должен знать те же определения для своего собственного кода. Ваша причина не включать bh в bc неверна. Каждый файл.c компилируется отдельно от каждого другого файла.c. Когда компилятор работает с ac, он начинается заново с bc. Неважно, что ac включил bh, потому что bc не имеет понятия, что ac даже существует. Целью защиты заголовка является предотвращение повторной обработки файла.h, если он включен несколько раз при компиляции данного файла.c. Без охраны объявления будут компилироваться несколько раз, что приведет к ошибкам в нескольких объявлениях существующих символов.

Другие вопросы по тегам