Компилируются ли h файлы
При разделении кода на несколько файлов, что именно должно помещаться в файл .h, а что - в файл .cpp?
Это проблема чистого стиля, но я считаю, что объявления C ++ помещаются в .hpp файл, а объявления C - в .h файл. Это очень полезно при смешивании кода C и C ++ (например, унаследованных модулей в C). @ThomasMatthews Имеет смысл. Эта практика часто используется? @lightningleaf: Да, эта практика часто используется, особенно при смешивании языков C ++ и C.Заголовочные файлы ( .h ) предназначены для предоставления информации, которая потребуется в нескольких файлах. Такие вещи, как объявления классов, прототипы функций и перечисления, обычно помещаются в файлы заголовков. Одним словом, «определения».
Файлы кода ( .cpp ) предназначены для предоставления информации о реализации, которая должна быть известна только в одном файле. В общем, тела функций и внутренние переменные, которые не должны / никогда не должны быть доступны другим модулям, принадлежат .cpp файлам. Одним словом, «реализации».
Самый простой вопрос, который нужно задать себе, чтобы определить, что принадлежит и где находится: «Если я изменю это, мне придется изменить код в других файлах, чтобы снова компилировать вещи?» Если ответ «да», он, вероятно, принадлежит заголовочному файлу; если ответ «нет», он, вероятно, принадлежит файлу кода.
Все хорошо, но с неточной терминологией. Одним словом, «декларации» - термин «определение» является синонимом «реализации». В заголовке должен быть только декларативный код, встроенный код, определения макросов и код шаблона; т.е. ничего, что создает экземпляр кода или данных. Я должен согласиться с Клиффордом. Вы используете декларацию и определение терминов довольно слабо и в некоторой степени взаимозаменяемо. Но они имеют точное значение в C ++. Примеры: объявление класса вводит имя класса, но не говорит, что в нем содержится. В определении класса перечислены все члены и дружественные функции. Оба могут быть без проблем помещены в файлы заголовков. То, что вы называете «прототипом функции», - это объявление функции . Но функция определение является то , что вещь , которая содержит код , функции и должны быть помещены в CPP-файл - если это не встроенное или (часть) шаблона. У них есть точные значения в C ++, у них нет точных значений в английском языке. Мой ответ был написан в последнем.Дело в том, что в C ++ это несколько сложнее, чем организация заголовка / источника C.
Что видит компилятор?
Компилятор видит один большой исходный файл (.cpp) с правильно включенными заголовками. Исходный файл - это единица компиляции, которая будет скомпилирована в объектный файл.
Итак, зачем нужны заголовки?
Потому что одному модулю компиляции может потребоваться информация о реализации в другом модуле компиляции. Таким образом, можно написать, например, реализацию функции в одном источнике и написать объявление этой функции в другом источнике, в котором необходимо ее использовать.
В этом случае есть две копии одной и той же информации. Что зло .
Решение - поделиться некоторыми подробностями. Хотя реализация должна оставаться в источнике, объявление общих символов, таких как функции, или определение структур, классов, перечислений и т. Д., Может потребоваться совместно.
Заголовки используются для размещения этих общих деталей.
Переместите в заголовок объявления о том, что нужно разделить между несколькими источниками
Ничего более?
В C ++ есть и другие вещи, которые можно поместить в заголовок, потому что они тоже должны быть общими:
- встроенный код
- шаблоны
- константы (обычно те, которые вы хотите использовать внутри переключателей . )
Переместите в заголовок ВСЕ, чем нужно поделиться, включая общие реализации
Значит ли это, что внутри заголовков могут быть источники?
Да. На самом деле, есть много разных вещей, которые могут быть внутри «заголовка» (т. Е. Разделены между источниками).
- Форвардные декларации
- объявления / определение функций / структур / классов / шаблонов
- реализация встроенного и шаблонного кода
Это становится сложным, а в некоторых случаях (циклические зависимости между символами) невозможно сохранить его в одном заголовке.
Заголовки можно разбить на три части
Это означает, что в крайнем случае у вас могут быть:
- заголовок форвардной декларации
- заголовок объявления / определения
- заголовок реализации
- источник реализации
Представим, что у нас есть шаблонный объект MyObject. У нас могло быть:
Вот это да!
В «реальной жизни» это обычно не так сложно. Большая часть кода будет иметь только простую организацию заголовка / источника с некоторым встроенным кодом в исходном коде.
Но в других случаях (шаблонные объекты, знающие друг друга) мне приходилось иметь для каждого объекта отдельное объявление и заголовки реализации с пустым источником, включая эти заголовки, просто чтобы помочь мне увидеть некоторые ошибки компиляции.
Еще одна причина разбить заголовки на отдельные заголовки может заключаться в ускорении компиляции, ограничении количества анализируемых символов до необходимого количества и избежании ненужной перекомпиляции источника, который заботится только о прямом объявлении при изменении реализации встроенного метода.
Вывод
Вы должны сделать организацию кода как можно более простой и как можно более модульной. Поместите как можно больше в исходный файл. В заголовках указывайте только то, чем нужно поделиться.
Но в тот день, когда у вас возникнут циклические зависимости между шаблонными объектами, не удивляйтесь, если ваша организация кода станет несколько более "интересной", чем простая организация заголовка / источника .
Прошло много времени с тех пор, как я смотрел C, я все забыл и смотрел на зенд с ошеломленным выражением лица.
О разнице между .c и .h
Не определяйте подпрограммы в .h. Определение функции должно быть помещено в .c, а .h - только для объявления. В противном случае функция будет повторно определена неправильно, если она будет цитироваться несколько раз.
.h только заявляет, что после компиляции код не создается
Конечно, если один .h содержится в нескольких .c, а в .h есть определения объектов (переменных или функций), возникнет повторяющаяся ошибка определения. Объявление может повторяться бесконечно много раз, а определение может быть только быть когда-то
Вообще говоря, файл C должен быть модулем. Если ваша программа имеет только один модуль (только один файл C), вам не нужно создавать H-файл. В противном случае ваш модуль определенно не является независимым, и реализация в вашем модуле должна вызываться другими модулями. На данный момент вам лучше сгенерировать файл заголовка (H-файл), в котором вы можете объявить свои функции общедоступными. Когда другие модули включают ваши файлы заголовков, вы можете использовать свои публичные объявления.
- Один C соответствует одному H, которым удобно управлять. Например, если у вас есть «feed_dog.c», добавьте еще «feed_dog.h»:
Фактически, не имеет значения, пишете ли вы функцию в H-файле, это просто не соответствует вашей привычке. Пока он записан в указанном выше формате, не имеет значения, сколько раз добавляется H-файл.
Это просто соглашение. В компиляторе нет разницы между .c и .h. Как использовать .c и .h полностью зависит от программиста, но для того, чтобы ваша программа была понятна позже и другие могли понять, пожалуйста, соблюдайте общепринятые соглашения. Креветки перед этими соглашениями уже много говорили об этом. Это похоже на то, как автомобиль едет направо по дороге. Это искусственное соглашение. Автомобиль (компилятор) сам не знает, что он движется влево. Используйте его справа. Если хотите, вы также можете называть исходные файлы и файлы заголовков любым суффиксом, но это может привести к сбою интегрированной среды компиляции и отладки, вам нужно написать свой собственный make-файл .
Чтобы сгенерировать окончательный исполняемый файл, необходимы некоторые целевые файлы, то есть нужен файл C, а этим файлам C нужна функция main. В качестве входа в исполняемую программу, затем мы начинаем с файла C, предполагая this Содержимое файла C выглядит следующим образом:
Содержимое файла заголовка выглядит следующим образом:
Теперь используйте этот пример, чтобы объяснить работу компилятора:
1. Этап предварительной обработки: компилятор использует файл C как единое целое. Сначала он считывает файл C и обнаруживает, что первое предложение и второе предложение содержат файл заголовка. Он будет искать эти два файла по всем путям поиска. будет обрабатывать макросы, переменные, объявления функций, включения вложенных файлов заголовков и т. д. в соответствующих файлах заголовков, обнаруживать зависимости, выполнять подстановки макросов и проверять, есть ли повторяющиеся определения и объявления, и, наконец, помещать эти файлы в Все файлы сканируются в этот текущий файл C, чтобы сформировать промежуточный "файл C"
2. На этапе компиляции, на предыдущем шаге, это эквивалентно сканированию тестовой переменной в этом заголовочном файле в промежуточный C-файл, затем тестовая переменная становится глобальной переменной в этом файле, а затем все промежуточные C-файлы. переменным и функциям файла выделяется место, каждая функция компилируется в двоичный код, а объектный файл создается в соответствии с конкретным форматом объектного файла. В объектном файле этого формата символьное описание каждой глобальной переменной и функции выглядит следующим образом: выполняются, и эти двоичные коды описаны в соответствии с определенными стандартами, организованными в целевой документ
3. На этапе подключения целевые файлы, созданные на предыдущем этапе, подключаются для создания окончательного исполняемого файла в соответствии с некоторыми параметрами. Основная работа заключается в перемещении функций и переменных каждого целевого файла, что эквивалентно двоичным кодам. объединены в один файл по определенным спецификациям
Вернемся к теме того, что написано в файле C и файле заголовка:
Теоретически, содержимое файла C и файла заголовка, если оно поддерживается языком C, вы можете написать что угодно. Например, если вы пишете тело функции в файле заголовка, если вы включаете это файл заголовка в любом файле C, вы можете изменить Эта функция компилируется в часть объектного файла (компиляция основана на файле C, если этот файл заголовка не включен ни в один файл C, этот код бесполезен), вы можете делать объявления функций, объявления переменных в файле C, объявление структуры, это не проблема! ! !
Тогда почему он должен быть разделен на файлы заголовков и файлы C? И почему функции, объявления переменных, объявления макросов и объявления структур обычно выполняются в заголовке? А как насчет реализации функции в файле C для определения переменной? ? Причины следующие:
1. Если тело функции реализовано в файле заголовка, то, если на него есть ссылки в нескольких файлах C, и несколько файлов C компилируются одновременно, объектный файл, сгенерированный им, связывается с исполняемым файлом, и каждая ссылка создается для этого Целевой файл, сгенерированный файлом C файла заголовка, содержит копию кода этой функции. Если эта функция не определена как локальная функция, то при подключении будет найдено несколько идентичных функций, и будет сообщено об ошибке.
2. Если вы определяете глобальную переменную в файле заголовка и присваиваете этой глобальной переменной начальное значение, тогда есть копии того же имени переменной в нескольких файлах C, которые ссылаются на этот файл заголовка. Ключ в том, что этой переменной назначается начальное значение. Таким образом, компилятор поместит эту переменную в раздел DATA, и, наконец, на этапе связывания в разделе DATA будет несколько идентичных переменных. Он не может объединить эти переменные в одну переменную, то есть только выделить пространство для этой переменной. Вместо нескольких пробелов, предполагая, что этой переменной не присвоено начальное значение в файле заголовка, компилятор поместит его в раздел BSS, а компоновщик выделит только одно пространство для хранения для нескольких переменных с одинаковыми имя в разделе BSS.
3. Если вы объявляете макросы, структуры, функции и т. Д. В файле C, то, если я хочу процитировать соответствующие макросы, структуры в другом файле C, я должен снова выполнить повторяющуюся работу. Если я изменю файл C Если вы забудьте изменить объявление в других файлах C, это не большая проблема, логика программы становится невообразимой, если вы поместите эти общедоступные материалы в файл заголовка, вам нужно указать только один файл C, если вы хотите использовать Это! ! ! Разве это не неудобно? Когда вы хотите изменить инструкцию, вам нужно только переместить файл заголовка. 4. Объявить структуры, функции и т. Д. В файле заголовка. Когда вам нужно инкапсулировать свой код в библиотеку, чтобы другие могли используйте свой код, вы не хотите публиковать исходный код, так как же люди используют вашу библиотеку? То есть как использовать каждую функцию в вашей библиотеке? ? Один метод - опубликовать исходный код, а другие могут использовать его по своему усмотрению. Другой - предоставить файлы заголовков, а другие будут просматривать прототип вашей функции из файла заголовка, чтобы они знали, как вызвать функцию, которую вы написали. точно так же, как вы вызываете функцию printf.То же, какие параметры внутри? ? Как ты узнал? ? Дело не в соответствующем заявлении в чужом заголовочном файле! ! ! Конечно, эти вещи стали стандартами C, даже если вы не просматриваете файлы заголовков других людей, вы все равно можете знать, как их использовать.
В чем разница между файлом ".h" и файлом ".c" в исходном коде программы ??
В исходном коде программы я увидел файл udp.h, а затем файл udp.c. Я не знаю, какая связь между ними? В чем разница?
- .c является исходным файлом серии языка C и существует в текстовой форме, тогда как серия .h является файлом заголовка, то есть файлом, в котором хранятся функции и глобальные переменные в серии C, поскольку функции в C инкапсулированы , то есть их нельзя увидеть в его коде.
Связь между файлом заголовка и файлом реализации. Что касается предыдущей взаимосвязи между ними, я должен говорить об этом с N лет назад
давным-давно, один раз за раз . Это была забытая эпоха, в компиляции The устройство распознает только файлы .c (.cpp)), но не знает возраст .h. В то время люди писали много файлов .c (.cpp). Постепенно люди обнаружили, что операторы объявления во многих файлах .c (.cpp) были одинаковыми, но им приходилось повторять их слово в слово. содержимое каждого файла .c (.cpp). Но еще более ужасающим является то, что при изменении одного из операторов вам нужно проверить все файлы .c (.cpp) и изменить операторы, ах
это конец света!
Хотя позже было много изменений, это использование продолжается и по сей день, но спустя долгое время люди забыли о причинах того года.
Когда дело доходит до файлов заголовков, давайте поговорим о их роли
Краткое описание роли файлов заголовков в высококачественном программировании на C / C ++, написанное Lin Rui GG:
(1) Вызов функций библиотеки через файлы заголовков. Во многих случаях исходный код неудобно (или не разрешается) предоставлять пользователям, пока пользователь предоставляет файлы заголовков и двоичные библиотеки. Пользователю нужно только вызвать библиотечные функции в соответствии с объявлением интерфейса в файле заголовка, и ему не нужно заботиться о том, как реализован интерфейс. Компилятор извлечет соответствующий код из библиотеки.
(2) Заголовочный файл может усилить проверку безопасности типов. Если интерфейс реализован или используется способом, несовместимым с объявлением в файле заголовка, компилятор укажет на ошибку.Это простое правило может значительно снизить нагрузку на программиста по отладке и исправлению ошибок.
Предварительная обработка является предшественником компилятора, и ее функция заключается в интеграции программных модулей, хранящихся в разных файлах, в полную исходную программу.
Я полностью согласен с точкой зрения брата Цянькуня Исяо, и основные вещи должны быть поняты. Я объясню пример брата Цянькуня Исяо ниже и завершу его запутанное время
Вот оригинальные слова улыбки Цянь Куня:
Его ответы следующие: Ответ: 1. Не обязательно. Этот пример явно избыточен. Но если функция в .c также должна вызывать другие функции в том же .c, тогда этот .c часто будет включать .h с тем же именем, поэтому вам не нужно беспокоиться об объявлении и последовательности вызовов (C language требует, чтобы вы использовали его перед объявлением и включали с тем же именем. H обычно ставится в начале .c). Многие проекты даже соглашаются на такой способ написания в виде спецификации кода, чтобы стандартизировать четкий код. 2. Ответ: Я уже ответил в 1. 3. Ответ: Нет. Человек, который задает этот вопрос, определенно непонятен, или просто хочет порыбачить в мутной воде. Что очень раздражает, так это то, что на многих экзаменах в Китае такие плохие вопросы. Боюсь, что у других будет четкая концепция, и я обязательно запутаю кандидатов.
Чтобы было ясно, компилятор компилируется в соответствии с модулем компиляции. Так называемый модуль компиляции относится к файлу .c и всем файлам .h, которые он включает. Наиболее интуитивно понятное понимание состоит в том, что в проекте можно использовать один файл. Содержит много файлов, в том числе точку входа в программу, которую мы обычно называем функцией main () (конечно, программу можно запустить без этой функции, подробности см. В моем блоге). точка входа. В этом случае модуль компиляции создает только объектный файл (файл .o, который в окнах называется .obj).
Этот пример содержит в общей сложности два модуля компиляции, а именно ac, main.c, согласно тому, что я сказал, генерируют только свои собственные файлы .o на этапе компиляции. Этот этап не имеет никаких отношений с другими файлами. И включает эту предварительную обработку инструкция происходит на этапе предварительной обработки (более ранняя фаза компиляции является просто предшественницей компилятора).
.h .c не обязательно является облаком. Нет смысла говорить об этом без компилятора. Помимо более глубоких, например, как ОС запускает это файл, структура PE (linux Elf) и т. д.
Компилятор должен сначала распознать этот файл, прежде чем он сможет его скомпилировать. Это предварительное условие. Если вы измените его расширение, сможет ли ваш компилятор распознать его?Поднимитесь на более высокий уровень, чтобы посмотреть на эту проблему, брат ХХ сказал, что это тоже хорошоЯ думаю, что брат ХХ сказал, что эти двое не должны считаться родственными, потому что имена одинаковые, а имена могут быть произвольными
Связь между двумя
(Возьмем меня в качестве примера. Если в таблице данных более 30 полей, я думаю, что заголовок большой. В таблицах, которые у меня сейчас есть, сотни полей. Я действительно надеюсь, что эксперт сможет изучить несколько хороших методов.Сделать наш мир немного лучше)
Третий вопрос Цянькуня Исяо очень показателен. Я много раз видел в Интернете, что текущий компилятор определенно не такой умный, и в этом нет необходимости. Давайте поговорим об этом ниже. Процесс обработки компилятором. (думаю, у новичков здесь есть вопросы, то есть они мало что знают об изменениях в процессе компиляции. h.c (.cpp),)
Позвольте мне рассказать о простом примере
Вы понимаете? Если вы не понимаете, позвольте мне сказать еще несколько слов. Когда мы изучили принципы компиляции, все мы знали, что компиляция выполняется поэтапно. На каждом этапе исходная программа конвертируется из одной представление в другое В общем случае последовательность следующая: исходная программа -> лексический разделитель -> анализатор синтаксиса -> семантический анализатор -> генератор промежуточного кода -> оптимизатор кода -> генератор кода -> целевая программа.
Среди этих шести действий два основных задействованных: диспетчер символов и обработчик ошибок.
Основная причина в том, что существует нечто, называемое таблицей символов, которая вас очаровывает. Фактически, таблица символов - это структура данных. Основная функция компилятора - записать исходный код. Идентификаторы, используемые в программе, собирают различную информацию об атрибутах, относящуюся к каждому идентификатору. Информация об атрибутах указывает место хранения / тип / объем идентификатора (действительный на этом этапе) и другую информацию. С точки зрения непрофессионала, это так объявление символа, такое как имя вашей функции, оно будет помещено в таблицу символов для регистрацииВ таблице символов хранится адрес входа вашей функции, количество параметров, возвращаемая информация и т. Д.На этапе подключения, в основном, имеет дело с соответствием между таблицей символов и вызовом в проекте, то есть то, что мы обычно называем разыменованием. После предыдущего, я не знаю, понимаете ли вы это или нет?
Наконец, я цитирую три пункта в конце Брата XXX: грамматику и концепции легко понять, но также трудно сказать. Есть три совета: 1. Избегайте головокружения, найдите время, чтобы больше подумать, читайте больше книг, 2. Читайте хорошие книги, когда читаете, и спрашивайте сильных людей, когда просите. Плохие книги и плохие люди дадут вам неверное представление и введут вас в заблуждение 3. Усердие в восполнении своей слабости - хороший урок, каждая тяжелая работа достойна;
Если вы думаете, что файлы .c и .h просто разные по названию, неизбежно придется понимать это немного поверхностно. Судя по истории op, развитие языка имеет тенденцию к появлению файлов oop..h . В этом заключается природа бита. .H. Файл хорошо скрыт. Эту истину нетрудно обнаружить. Пока вы откроете свой собственный файл .h, это будет очевидно. Поэтому я согласен с Брат ХХХ, что улыбка Цянькуня поверхностна.
Но посмотрите на это с другой стороны:
(Что касается реализации компилятора. Пока не знаю. Но верю. Нравится)
Здравствуйте, physic, Вы писали:
P>как можно назвать обработку и подклучение *.h файла в C++ проекте?
Дело в том что *.h файл подключается к *.cpp или *.h файлу препроцессором, а вот когда у компилятора есть полностью скомпонованная единица трансляции *.cpp + все необходимые *.h файлы, тогда компилятор компилит весь получившийся текст. Отсюда можно заключить что *.h файл компилится после обработки препроцессора.
как можно назвать обработку и подклучение *.h файла в C++ проекте?Здравствуйте, physic, Вы писали:
P>как можно назвать обработку и подклучение *.h файла в C++ проекте?
Здравствуйте, Alxndr, Вы писали:
A>Здравствуйте, physic, Вы писали:
P>>как можно назвать обработку и подклучение *.h файла в C++ проекте?
A>Препроцессингом?
Здравствуйте, Alxndr, Вы писали:
A>Здравствуйте, physic, Вы писали:
P>>как можно назвать обработку и подклучение *.h файла в C++ проекте?
A>Препроцессингом?
В .h объявляются ф-ии, т.д. Возможна реализация, но не инициализация. Таким образом, всё что будет необходимо твоему *.c будет взято из *.h, остальное игнорируется. Определение включению заголовочных файлов не скажу, не задавался таким вопросом, раньше не где ни встречал.
It is always bad to give advices, but you will be never forgiven for a good one.Oscar Wilde
*.h файлы компилятором не обрабатываются.
Обрабатываются *.c (*.cpp и т.п.) файлы.
Включение (рекурсивное) инклюдов выполняется при препроцессинге.
Здравствуйте, Alxndr, Вы писали:
A>*.h файлы компилятором не обрабатываются.
Вот тут я не согласен . В *.h файле те же объявления которые могли бы быть и в *.сpp файле, и эти объявления компилируются в бинарный код.
Здравствуйте, physic, Вы писали:
P>Вот тут я не согласен . В *.h файле те же объявления которые могли бы быть и в *.сpp файле, и эти объявления компилируются в бинарный код.
Ачто делает этот год?
Здравствуйте, physic, Вы писали:
P>Здравствуйте, Alxndr, Вы писали:
A>>*.h файлы компилятором не обрабатываются.
P>Вот тут я не согласен . В *.h файле те же объявления которые могли бы быть и в *.сpp файле, и эти объявления компилируются в бинарный код.
После фазы препроцессинга иммем единицу трансляции следующего содержания:
Кури, вообщем, Стандарт и книги.
Здравствуйте, physic, Вы писали:
P>Здравствуйте, physic, Вы писали:
P>>как можно назвать обработку и подклучение *.h файла в C++ проекте?
P>Дело в том что *.h файл подключается к *.cpp или *.h файлу препроцессором, а вот когда у компилятора есть полностью скомпонованная единица трансляции *.cpp + все необходимые *.h файлы, тогда компилятор компилит весь получившийся текст. Отсюда можно заключить что *.h файл компилится после обработки препроцессора.
Путаница в терминологии
Компилятор компилирует единицы трансляции.
В системах, где исходные тексты хранятся в файлах, единица трансляции — это файл, обработанный препроцессорос с рекурсивно включенными *.h-файлами.
Здравствуйте, physic, Вы писали:
P>Вот тут я не согласен . В *.h файле те же объявления которые могли бы быть и в *.сpp файле, и эти объявления компилируются в бинарный код.
При чем здесь объявления? .
Вот это и подается на вход компилятору. Как это не укладывается в твою концепцию? It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde Компилятор строит свои внутренние таблицы: функция, параметр, возвращаемое значение; а более что ещё можно сделать?
Потом эти таблицы не трогаются если *.h не меняется. А если меняется, то таблица перестраивается, и компилятся все файлы куда он входил. Что-то вроде этого. Что за код может сгенириться из объявлений?
Crackjack wrote:
> A>Препроцессингом?
>
> В .h объявляются ф-ии, т.д. Возможна реализация, но не инициализация.
Там возможно всё что угодно. Правда в некоторых случаях (когда один h включается из нескольких cpp) программа не слинкуется.
> Таким образом, всё что будет необходимо твоему *.c будет взято из *.h,
> остальное игнорируется. Определение включению заголовочных файлов не
> скажу, не задавался таким вопросом, раньше не где ни встречал.
Обработка .h файлов идёт до компиляции. Компилятор вообще ничего про файлы не знает.
.cpp и .h файлы — чистая условность. Просто так договорились, языку до этого пофиг. Называй файлы как хочешь и что
угодно куда угодно подключай.
именно
Плюс можно вспомнить про precompiled header(msdn). Он применяется как раз для того, чтобы не компилировать многократно одни и те же куски кода, и представляет собой the state of compilation at a certain point.
Здравствуйте, physic, Вы писали:
P>как можно назвать обработку и подклучение *.h файла в C++ проекте?
Здравствуйте, Crackjack, Вы писали:
P>>>как можно назвать обработку и подклучение *.h файла в C++ проекте?
A>>Препроцессингом?
C>В .h объявляются ф-ии, т.д. Возможна реализация, но не инициализация. Таким образом, всё что будет необходимо твоему *.c будет взято из *.h, остальное игнорируется. Определение включению заголовочных файлов не скажу, не задавался таким вопросом, раньше не где ни встречал.
Здравствуйте, physic, Вы писали:
P>как можно назвать обработку и подклучение *.h файла в C++ проекте?
Прикольно реализовано в Boost.Test, там реализация лежит в *.ipp которая инклюдиться в файл, в первый раз такое вижу.
Здравствуйте, Chipsеt, Вы писали:
C>Прикольно реализовано в Boost.Test, там реализация лежит в *.ipp которая инклюдиться в файл, в первый раз такое вижу.
Эта реализация совершенно случайно не генерируется автоматом? (просто гипотеза, нет времени сейчас посмотреть).
Практически: существуют соглашения относительно файлов .h, так что вы можете безопасно включать этот файл в несколько других файлов в вашем проекте. Заголовочные файлы предназначены для общего доступа, а файлы кода - нет.
Давайте возьмем ваш пример определения функций или переменных. Предположим, что ваш заголовочный файл содержит следующую строку:
Теперь, если у вас есть только один кодовый файл и один заголовочный файл, это, вероятно, работает просто отлично:
Однако, если у вас есть два файла кода, это ломается:
Это ломается, особенно на этапе компоновщика, потому что теперь у вас есть два символа в одном исполняемом файле, которые имеют один и тот же символ, и компоновщик не знает, что он должен делать с этим. Когда вы включаете свой заголовок в code1, вы получаете символ «x», а когда вы включаете свой заголовок в code2, вы получаете другой символ «x». Компоновщик не знает о вашем намерении, поэтому выдает ошибку:
Это опять-таки просто компоновщик, говорящий, что он не может решить тот факт, что теперь у вас есть два символа с одинаковым именем в одном и том же исполняемом файле.
Для небольших программ хранение всей кодовой базы в одном файле .cpp (или даже в одном файле .h ) работает нормально, потому что число строк кода, которые компилятор должен загрузить в память, невелико (относительно в оперативную память компьютера).
Но представьте, что вы работаете над монстровой программой с десятками миллионов строк кода - да, такие вещи существуют. Загрузка такого большого количества кода в ОЗУ сразу же, вероятно, подчеркнет возможности всех, кроме самых мощных компьютеров, что приведет к чрезмерно долгому времени компиляции или даже к полному отказу.
Поэтому, когда вы изменили функцию в 375-ом .cpp файле из 700 .cpp файлов в вашей программе, и теперь вы хотите протестировать свою модификацию, компилятору нужно только перекомпилировать эту одну <
Файлы .cpp также значительно облегчают решение проблем со связью. Например, если вы хотите иметь глобальную переменную, определить эту глобальную переменную в файле .cpp (и, возможно, объявить extern для нее в файле .h) просто; если OTOH вы хотите сделать это в файле .h, вам нужно быть очень осторожным, иначе вы получите ошибки дубликата символов от вашего компоновщика и / или незначительные нарушения правила One Definition Rule, которое вернется чтобы укусить тебя позже.
Файлы .cpp компилируются в файлы .obj . Они не знают о существовании какого-либо другого файла .cpp и скомпилированы по отдельности. Вот почему нам нужно объявлять вещи, прежде чем мы их используем - иначе компилятор не будет знать, существует ли функция, которую мы пытаемся вызвать, в другом файле .cpp .
Мы используем файлы заголовков для совместного использования объявлений среди нескольких файлов .cpp , чтобы избежать необходимости писать один и тот же код снова и снова для каждого отдельного файла .cpp .
НАСТОЯЩЕЕ отличие состоит в том, что ваша среда программирования перечисляет файлы .h и .cpp отдельно. И / или заполняет диалоги file-browser соответственно. И / или пытается скомпилировать файлы .cpp в форму объекта (но не делает этого с файлами .h). И что угодно, в зависимости от того, какую среду / среду вы используете.
Второе отличие заключается в том, что people предполагают, что ваши файлы .h являются заголовочными файлами, а файлы .cpp - исходными файлами кода.
Если вас не волнуют люди или среды разработки, вы можете поместить любую чертову вещь в файл .h или .cpp и вызывать их как хотите. Вы можете поместить свои объявления в файл .cpp и назвать его «включаемым файлом», а свои определения - в файл .pas и назвать его «исходным файлом».
Я должен делать подобные вещи, работая в стесненных условиях .
Заголовочные файлы не были частью первоначального определения c. Мир прекрасно обходился без них. Открытие и закрытие большого количества заголовочных файлов замедлило компиляцию c, поэтому мы получили предварительно скомпилированные заголовочные файлы. Предварительно скомпилированные заголовочные файлы ускоряют компиляцию и компоновку исходного кода, но не быстрее, чем просто написание ассемблера, машинного кода или любой другой вещи, которая не использует преимущества других людей. или среда разработки .
полезно помещать объявления в заголовочный файл, а определения в исходный файл кода. Вот почему вы должны сделать это. Нет требования .
В чем НАСТОЯЩАЯ разница между файлами .h и .cpp?
Они оба в основном просто текстовые файлы. С определенной точки зрения, их единственным отличием является имя файла.
Однако многие инструменты, связанные с программированием, обрабатывают файлы по-разному в зависимости от их имени. Например, некоторые инструменты обнаружат язык программирования: .c скомпилирован как язык C, .cpp скомпилирован как C ++, а .h вообще не скомпилирован.
Для заголовочных файлов имя не имеет значения для компилятора. Имя может быть .h или .header или что-то еще, это не влияет на то, как его включает в себя препроцессор. Однако во избежание путаницы рекомендуется придерживаться общей конвенции.
Я заметил, что просто определение функций в .h файлах работает просто отлично.
Функции объявлены не встроенными? Вы когда-нибудь включали заголовочный файл в несколько единиц перевода? Если вы ответили утвердительно на оба вопроса, значит, ваша программа плохо сформирована. Если вы этого не сделали, то это объяснило бы, почему вы не столкнулись с какими-либо проблемами.
Это действительно уменьшает время компиляции?
Да. Разделение определений функций на меньшие единицы перевода действительно может сократить время на компиляцию указанных единиц перевода по сравнению с компиляцией больших единиц перевода.
Это потому, что выполнение меньшего количества работы занимает меньше времени. Важно понимать, что другие единицы перевода не нужно перекомпилировать, когда модифицируется только одна. Если у вас есть только одна единица перевода, то вы должны скомпилировать ее, то есть программу целиком.
Несколько модулей перевода также лучше, потому что они могут быть скомпилированы параллельно, что позволяет использовать преимущества современного многоядерного оборудования.
Нужно ли быть чем-то еще? Необходимость подождать несколько минут для компиляции вашей программы вместо одного дня значительно повышает скорость разработки.
Есть и другие преимущества относительно организации файлов. В частности, довольно удобно иметь возможность определять разные реализации для одной и той же функции для разных целевых систем, чтобы иметь возможность поддерживать несколько платформ. С заголовочными файлами вы должны делать трюки с макросами, а с исходными файлами вы просто выбираете, какие файлы компилировать.
Другой вариант использования, где реализация функций в заголовке не является вариантом, - это распространение библиотеки без исходного кода, как это делают некоторые поставщики промежуточного программного обеспечения. Вы должны указать заголовки, иначе ваши функции не могут быть вызваны, но если весь ваш источник находится в заголовках, то вы отказались от своих коммерческих секретов. Скомпилированные источники должны быть, по крайней мере, перепроектированы.
Читайте также: