C ++: Понимание заголовочных файлов & amp; Заголовки с примером простого добавления

Я не могу разобраться с заголовками и охранниками заголовков. Я прочитал другие вопросы и ответы на них, но я все еще не могу сделать эту работу в Visual Studio 2013:

main.cpp

#include "stdafx.h"#include <iostream>
#include "add.h"
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}

add.cpp

#include "stdafx.h" //ADDED LATER; NOW WORKING (AND SEE QUESTION 2 BELOW)
#include "add.h" //ADDED LATER; NOR WORKING (AND SEE QUESTION 2 BELOW)
int add(int x, int y) {
return x + y;
}

add.h

#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif

Когда я компилирую, окно консоли мигает на экране, а затем исчезает. Список ошибок содержит:

Ошибка 1 ошибка LNK2019: неразрешенный внешний символ «int __cdecl
add (int, int) «(? add @@ YAHHH @ Z), на который есть ссылка в функции
_wmain c: \ Users \ Danny \ Documents \ visual studio 2013 \ Проекты \ Программа дополнения \ main \ main.obj main

Ошибка 2: ошибка LNK1120: 1 не устранена
externals c: \ users \ danny \ Documents \ visual studio
2013 \ Проекты \ Дополнительная программа \ Debug \ main.exe main


1. Как работают заголовки и защита заголовков? Я вижу, как по add.h, это делает main.cpp знать о декларации add(int x, int y), но тогда как оно находит свое определение?


2. Что я ошибся в своем коде?

Мой код сейчас компилируется. Причина, по которой мой код не компилировался, заключалась в том, что я собирался Файл> Новый> Файл … чтобы добавить файлы в мой проект, в отличие от добавления их через Исходные файлы а также Заголовочные файлы разделы Обозреватель решений в Visual Studio. Мне также нужно было добавить #include "stdafx.h в файл add.cpp.

0

Решение

Думайте об этом так: каждый .cpp Файл предварительно обрабатывается, а затем компилируется полностью отдельно от других файлов.

Итак, давайте сначала препроцесс main.cpp, Это предполагает просмотр всех строк, начинающихся с #, Файл main.cpp только имеет #include строки, которые просто копируют содержимое файла, который они включают. Я собираюсь представлять содержимое stdafx.h а также iostream с комментарием, но я на самом деле скопировать содержимое add.h в:

// Contents of stdafx.h
// Contents of iostream
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif

int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}

Теперь посмотрите, что содержимое add.h были введены в main.cpp? И так получилось, что это ввело еще несколько директив препроцессора, поэтому нам нужно будет делать то, что они говорят. Первый проверяет, если ADD_H еще не определено (в этом файле), что не является, и поэтому оставляет все до #endif:

// Contents of stdafx.h
// Contents of iostream
#define ADD_H
int add(int x, int y);

int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}

Теперь оставшаяся директива препроцессора определяет ADD_H и мы остались с финалом блок перевода:

// Contents of stdafx.h
// Contents of iostream
int add(int x, int y);

int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}

Теперь этот файл можно скомпилировать. Если вы вызываете функцию, такую ​​как addкомпилятору нужно только видеть объявление этой функции для успешной компиляции. Ожидается, что функция будет определена в некоторых Другой переводческий блок.

Итак, теперь давайте посмотрим на предварительную обработку add.cpp, По факту, add.cpp не имеет никаких директив предварительной обработки, поэтому ничего не должно произойти. Как правило, вы бы #include "add.h", но ваша программа все равно будет компилироваться, если вы этого не сделаете. Итак, после предварительной обработки у нас все еще есть:

int add(int x, int y) {
return x + y;
}

Затем это компилируется, и теперь у нас есть определение add функция.

В конце концов .cpp файлы были скомпилированы, затем они связанный. Линкер отвечает за то, чтобы скомпилированный main.cpp использует функцию add и так ищет свое определение. Находит определение в скомпилированном add.cpp и связывает их вместе.


Тогда вы можете удивиться, почему у нас вообще есть охрана. В этом примере это казалось бесполезным. Правильно, в этом примере это не имело никакого смысла. Предусмотрено включение защиты, чтобы предотвратить включение одного и того же заголовка дважды в один файл. Это может легко произойти, если у вас есть более сложная структура проекта. Однако давайте посмотрим на нереальный пример, где main.cpp включает в себя add.h дважды:

#include "stdafx.h"#include <iostream>
#include "add.h"#include "add.h"
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}

Предварительная обработка дает вам:

// Contents of stdafx.h
// Contents of iostream
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif

int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}

Первый #ifndef будет процесс, он увидит, что ADD_H еще не определено, и все до #endif останется. Это тогда определяет ADD_H,

Потом второй #ifndef обрабатывается, но на этом этапе ADD_H был определен, так что все до #endif будут отброшены

Это очень важно, потому что наличие нескольких определений функции (и многих других) приведет к ошибке.

4

Другие решения

Среда IDE компилирует каждый файл .cpp по очереди, чтобы создать объектный файл (машинный код) для этого конкретного файла.

После всего этого он записывает биты, чтобы сформировать исполняемый файл. IDE знает, что должно быть связано с чем.

Это немного упрощенный ответ

1

По вопросам рекламы [email protected]