




Вот что меня всегда сбивало с толку:
Это ищет в пути заголовка:
#include <stdio.h>
Это ищет в вашем локальном каталоге:
#include "myfile.h"
Второе, что вы должны сделать с КАЖДЫМ заголовком:
myfilename.h:
#ifndef MYFILENAME_H
#define MYFILENAME_H
//put code here
#endif
Этот шаблон означает, что вы не можете отказаться от переопределения заголовков в вашей компиляции (Приветствия orsogufo за то, что он указал мне, что это называется «защитой включения»). Прочтите немного о том, как компилятор C на самом деле компилирует файлы (перед компоновкой), потому что это сделает мир #define и #include очень понятным для вас, компилятор C, когда дело доходит до синтаксического анализа текста, не очень разумный. (Сам компилятор C - другое дело)
И большинство компиляторов допускают эквивалент #pragma once
@xtofi: Нет. Это расширение MS. Очень немногие другие компиляторы поддерживают его.
@Spence: Нет, это неправильно. Второй include также ищет набор каталогов (просто другой набор)
@Martin: Действительно - только MS и gcc поддерживают #pragma один раз (а последний официально не поддерживает). Особенно сложно дать четкое определение понятию «один и тот же файл». Почему у нас нет эквивалента php "include" vs "require"?
@xtofl: Согласен, было бы неплохо. Но даже php не работает по той же причине: us2.php.net/require
_H и прописные буквы тоже важны. Однажды, когда у меня было меньше опыта, я использовал защиту включения с тем же именем и регистром, что и определение класса в файле ... какое-то время меня раздражало то, что он не компилируется.
Мартин прав. разница между "" и <> не определена. его реализация определяет, в чем разница. большинство компиляторов, однако, сначала обращаются к пути, относящемуся к файлу, когда используется "".
В основном вам нужно понимать, где заголовки include НЕ требуются, например. форвардная декларация. Также постарайтесь убедиться, что включаемые файлы компилируются один за другим, и вставляйте #includes в h-файлы только тогда, когда это необходимо (например, шаблоны).
Я думаю, что то, о чем вы говорили, - это то, что мне нужно. Все вышеперечисленное достаточно простое, чтобы все это знали.
Заголовочные файлы - это способ C разделить интерфейс и реализацию. Они делятся на два типа: стандартные и определяемые пользователем файлы заголовков. Стандартный файл заголовка, такой как string.h, позволяет нам получить доступ к функциям базовой библиотеки C. Вы должны # включать его в каждый файл .c, который использует соответствующие функции. Обычно здесь используются скобки, как в #include Определяемый пользователем файл заголовка предоставляет вашу реализацию функций другим программистам или другим частям вашего кода C. Если вы реализовали модуль под названием рациональный.c для вычислений с рациональными числами, он должен иметь соответствующий файл рациональный.h для его общедоступного интерфейса. Каждый файл, который использует эту функциональность, должен # включать рациональный.h, а также рациональный.c должен # включать его. Обычно это делается с помощью #include "rational.h ". Часть компиляции, которая выполняет #includes, называется Препроцессор C. В основном это замена текста и вставка текста. Спенс прав в своем шаблоне предотвращения дублирования #includes, которые портят пространство имен. Это основа включения, GNU Make дает вам гораздо больше мощности, а также гораздо больше проблем.
Вы используете #include "yourfile.h", если yourfile.h находится в текущем рабочем каталоге.
и #include <yourfile.h>, если путь к файлу yourfile.h был включен в каталоги включения C++ (где-то в конфигурации, например: c:\mylib\yourfile.h, путь c:\mylib\ должен быть указан как каталог включения)
Также вы можете включить .cpp и .hpp (h плюс плюс).
Существует определенный набор файлов, которые можно записать как: #include <iostream>. Для работы этого конкретного примера необходимо указать using namespace std;.
Есть очень хорошее программное обеспечение, которое интегрировано с Visual C++ от Microsoft и показывает пути включения. http://www.profactor.co.uk/includemanager.php
В дополнение к другим комментариям помните, что вам не нужно # включать заголовок в другой заголовок, если у вас есть только указатель или ссылка. Например.:
Требуется заголовок:
#include "Y.h"
class X
{
Y y; // need header for Y
};
Заголовок не требуется:
class Y;
class X
{
Y* y; // don't need header for Y
};
//#include "Y.h" in .cpp file
Второй пример компилируется быстрее и имеет меньше зависимостей. Это может быть важно в больших базах кода.
Спасибо, это так называемое форвардное объявление?
Ага, это предварительное заявление. Очень полезно для ускорения компиляции. Это работает только тогда, когда компилятору не нужны детали; вы не можете использовать его для базовых классов, реальных членов и тому подобного.
Проверьте Дискуссия при использовании #include<filename.h>
а #include<filename> для C++ включает библиотеки C.
Обновлено: Энди Брайс также кратко высказался об этом.
Следуя нулевому ответу, самое важное, о чем нужно подумать, - это то, где вы помещаете свои # include.
Когда вы пишете #include, препроцессор буквально включает содержимое файла, который вы указываете в текущем файле, включая любые #includes в этих файлах. Это, очевидно, может привести к очень большим файлам во время компиляции (раздувание coad), поэтому вам нужно внимательно подумать, нужен ли #include.
В стандартном макете файла кода, где у вас есть файл .h для класса с объявлениями класса и функции, а затем файл реализации .cpp, вы должны быть осторожны с количеством #includes, которые входят в файл заголовка. Это потому, что каждый раз, когда вы вносите изменения в файл заголовка, любые файлы, которые также включают его (то есть, которые используют ваш класс), также должны быть перекомпилированы; если в самом заголовке много включений, то каждый файл, использующий этот класс, значительно раздувается во время компиляции.
По возможности лучше использовать форвардные объявления, чтобы вы могли записать сигнатуры методов и т. д., А затем # включить соответствующие файлы в файл .cpp, чтобы вы могли фактически использовать классы и структуры, от которых зависит ваш код.
//In myclass.h
class UtilClass; //Forward declaration of UtilClass - avoids having to #include untilclass.h here
class MyClass
{
MyClass();
~MyClass();
void DoSomethingWithUtils(UtilClass *util); //This will compile due to forward declaration above
};
//Then in the .cpp
#include utilclass.h
void MyClass::DoSomethingWithUtils(UtilClass *util)
{
util->DoSomething(); //This will compile, because the class definition is included locally in this .cpp file.
}
#include utilclass.h;), так что вам лучше попробовать по-настоящему скомпилировать это раньше ...
Таким образом, ваш компилятор может поддерживать 2 уникальных пути поиска для включаемых файлов:
Неформально мы могли бы назвать систему include path, а пользователя include path.
#include <XX> ищет системный путь включения.
#include "XX" ищет путь включения пользователя, затем путь включения системы.
Проверка проекта стандарта n2521:
Раздел 16.2:
2 A preprocessing directive of the form
# include < h-char-sequence> new-line
searches a sequence of implementation-defined places for a header identified
uniquely by the specified sequence between the < and > delimiters, and
causes the replacement of that directive by the entire contents of the
header. How the places are specified or the header identified is
implementation-defined.
3 A preprocessing directive of the form
# include " q-char-sequence" new-line
causes the replacement of that directive by the entire contents of the
source file identified by the specified sequence between the " " delimiters.
The named source file is searched for in an implementation-defined manner.
If this search is not supported, or if the search fails, the directive is
reprocessed as if it read
# include < h-char-sequence> new-line
with the identical contained sequence (including > characters, if any)
from the original directive.
Примером этого может быть gcc
-isystem <dir> Add <dir> to the start of the system include path
-idirafter <dir> Add <dir> to the end of the system include path
-iwithprefix <dir> Add <dir> to the end of the system include path
-iquote <dir> Add <dir> to the end of the quote include path
-iwithprefixbefore <dir> Add <dir> to the end of the main include path
-I <dir> Add <dir> to the end of the main include path
Чтобы узнать, где находится ваш gcc, сделайте следующее:
g++ -v -E -xc++ /dev/null -I LOOK_IN_HERE
#include "..." search starts here:
#include <...> search starts here:
LOOK_IN_HERE
/usr/include/c++/4.0.0
/usr/include/c++/4.0.0/i686-apple-darwin9
/usr/include/c++/4.0.0/backward
/usr/local/include
/usr/lib/gcc/i686-apple-darwin9/4.0.1/include
/usr/include
/System/Library/Frameworks (framework directory)
/Library/Frameworks (framework directory)
End of search list.
Итак, как использовать эти знания. Есть несколько школ мысли. Но я всегда перечисляю свои библиотеки от самых частных до самых общих.
Пример
Файл: plop.cpp
#include "plop.h"
#include "plop-used-class.h"
/// C Header Files
#include <stdio.h> // I know bad example but I drew a blank
/// C++ Header files
#include <vector>
#include <memory>
Таким образом, если в заголовочный файл "plop-used-class.h" должен быть включен <vector>, это будет обнаружено компилятором. Если бы я поместил <вектор> вверху, эта ошибка была бы скрыта от компилятора.
... какие компиляторы поддерживают различие системный путь vs. путь пользователя? Похоже, вы имеете в виду исключительно GCC ...
@Wolf Я процитировал стандарт (как это было в 09). Что говорит о том, как файл найден, это implementation-defined. Затем я покажу, как реализация gcc в качестве «примера» (gcc является доминирующим компилятором C++ в то время, clang существует, но едва ли можно использовать в 09, не относящемся к 2011 году, компилятор MS cl, похоже, имеет только один путь поиска).
Ясно спасибо. Итак, вы перевели места, определяемые реализацией в система включает путь.
@Wolf Помимо ответа на вопрос именно цитатой из стандарта. Затем я проиллюстрировал реальный пример того, как реализация интерпретирует implementation-defined для решения реальной ситуации.
Просто дополнение к ответу Энди Брайса, вы также можете обойтись предварительными объявлениями для возвращаемых значений функций:
class Question;
class Answer;
class UniversityChallenge
{
...
Answer AskQuestion( Question* );
...
};
Вот ссылка на вопрос, который я задал некоторое время назад, с хорошими ответами http://bytes.com/groups/c/606466-forward-declaration-allowed.
Is there any material about how to use #include correctly?
Я настоятельно рекомендую раздел SF: Исходные файлыОсновные принципы C++ в качестве хорошей отправной точки.
I didn't find any C/C++ text book that explains this usage in detail.
Многие общепринятые представления о физическом составе проектов C++, вероятно, можно найти в «Крупномасштабная разработка программного обеспечения на C++» Джона Лакоса.
In formal project, I always get confused in dealing with it.
Вы в хорошей компании. До Модули C++ 20#include был единственным практическим способом составления единиц перевода C++ из нескольких файлов. Это простая, ограниченная возможность, с помощью которой препроцессор по существу копирует / вставляет целые файлы в другие файлы. Результирующий ввод компилятора часто бывает огромным, и работа обычно повторяется от одной единицы трансляции к другой.
Шаблон называется «включить охранник».