Что делает и не делает компилятор MSVC ++ 2008 Express Editon - PullRequest
2 голосов
/ 15 июня 2011

Мне было интересно, заботится ли компилятор msvc ++ 2008 о включении нескольких заголовков одного и того же файла, учитывая этот пример:
main.cpp

#include "header.h"
#include "header.h"

Будет ли компилятор включать этот файл несколько раз или только один? (Я знаю, что могу использовать "трюк" #ifndef, чтобы предотвратить это) Кроме того, если я включу "header.h", который содержит 10 функций, но я только вызываю или использую 2, он все равно будет включать все 10 или только те 2, которые мне нужны, и все их потребности?

Ответы [ 5 ]

4 голосов
/ 15 июня 2011

#include в основном является синонимом «копировать и вставить». Если вы делаете идентичные #include s, содержимое этого заголовочного файла будет копироваться и вставляться дважды, последовательно.

Что касается вашего второго вопроса, он не имеет смысла. #include s выполняются препроцессором , который запускается перед компилятором и компоновщиком . Препроцессор не знает и не заботится о содержимом заголовочного файла, он просто копирует и вставляет его. Компоновщик может удалить ненужные функции, но это совершенно не зависит от препроцессора.

3 голосов
/ 15 июня 2011

Нет, компилятор (или, точнее, препроцессор) не позаботится об этом "автоматически". Не в Visual C ++ 2008 или в любой другой версии. И ты действительно не хотел бы этого.

Есть два стандартных способа сделать это. Вы должны выбрать один из них.

Первый известен как включает охранников . Это "#ifndef трюк", который вы упомянули в своем вопросе. Но это, конечно, не "трюк". Это стандартная идиома для обработки этой ситуации при написании кода на C ++, и любой другой программист, который смотрит на ваш исходный файл, почти наверняка ожидает, что увидит, что где-то есть охранники.

Другой использует преимущества функции VC ++ (которая также появилась в нескольких других наборах инструментов C ++) для выполнения, по сути, того же самого способа, который несколько проще набирать. Включив строку #pragma once в верхней части файла заголовка, вы даете указание препроцессору включать файл заголовка только один раз на единицу перевода. Это имеет ряд других преимуществ по сравнению с охраной, но здесь они не особенно актуальны.

Что касается вашего второго вопроса, компоновщик позаботится об «оптимизации» функций, которые вы никогда не вызываете в своем коде. Но это последний этап компиляции, и он не имеет ничего общего с #include, который обрабатывается препроцессором, как я упоминал выше.

1 голос
/ 15 июня 2011

Препроцессор MSVC 20xx (не компилятор - компилятор никогда не видит директивы препроцессора) ни в каком смысле не "заботится" о множественных # включениях одного и того же файла.Если файл #include дважды, препроцессор подчиняется #include и включает файл два раза.(Представьте себе хаос, если препроцессор даже подумал о попытке исправить «плохое» поведение #include вашего исходного файла.)

Поскольку препроцессор очень дотошный и осторожный в выполнении ваших инструкций, каждый #include файл должен защищатьсам от того, что # дважды включен.Эта защита - это то, что мы видим, когда находим такие строки в верхней части файла заголовка:

 #ifndef I_WAS_ALREADY_INCLUDED   // if not defined, continue with include
 #define I_WAS_ALREADY_INCLUDED   // but make sure I'm not included again

    [ header-file real contents ]

 #endif  // I_WAS_ALREADY_INCLUDED

Когда вы пишете файл заголовка, вы всегда должны быть уверены, что защитите его таким образом.

0 голосов
/ 15 июня 2011

Препроцессор будет включать в себя 2 раза эти заголовки.Вот почему в заголовочных файлах требуется защита.Насколько я знаю, компоновщик в большинстве случаев удаляет код (функции), более новые, используемые для уменьшения размера исполняемого файла.

0 голосов
/ 15 июня 2011

Почему тебя это волнует? Это не увеличивает нагрузку на компилятор, потому что компилятор условно (например, с #ifdef s) исключает код, который не нужно компилировать.

...