#cpp #компоновщик
На этот вопрос уже даны ответы здесь: В каком случае нужно определять функцию в заголовочном файле? (5 ответов) Что такое “Правило одного определения” (One definition rule)? (1 ответ) Закрыт 2 года назад. Рассмотрим следующий пример: // file header1.h #includevoid foo() { std::cout << "Foo" << '\n'; } // file source1.cpp #include "header1.h" // file main.cpp #include "header1.h" int main() { return 0; } В связи с тем, что определение foo находится в хедере (что не очень хорошо), который включён в более чем один .cpp файл, линкер честно выдает ошибку наподобие: multiple definition of foo ... first defined in main.o ... Одно из решений - сделать foo статической функцией, что обеспечит одно определение в объектных файлах: static foo() { ... } второе: inline foo() { ... } третье: static inline foo() { ... } Вопросы: Почему inline функция тоже решает эту проблему? Какие принципиальные отличия у этих решений?
Ответы
Ответ 1
inline решает эту проблему потому, что спецификация языка этого требует. Правило Одного Определения (One Definition Rule) для inline функций ясно говорит, что inline функция с внешним связыванием может определяться в программе много раз в разных единицах трансляции (точнее: должна определяться везде, где одна используется и везде - одинаково). А уж как компиляторы/линкеры реализуют это требование - это их проблемы. Фактически, если такая функция породила тело в нескольких объектных файлах (т.е. не все ее вызовы заинлайнились), то линкеру будет предписано не ругаться на тему "multiple definition", а молча выбрать одно-единственное тело и остальные выбросить. Так как "классический" формат объектного файла не позволяет определить, где начинается и где заканчивается тело конкретной функции, для целей возможного будущего удаления компилятор их обычно помещает в выделенные секции объектного файла. Принципиальное отличие между inline и static вариантом заключается в том, что inline функция сохраняет внешнее связывание (external linkage) и ведет себя во всех отношениях как функция со внешним связыванием. Например, если разные единицы трансляции попробуют взять адрес inline функции, то везде обязательно должно получиться одно и то же значение. Статические переменные, определенные внутри такой inline функции тоже существуют в единственном экземпляре во всей программе, как и в любой другой функции со внешним связыванием. В static варианте наоборот, функция получает внутреннее связывание (internal linkage) - каждая единица трансляции получает свою копию функции со своим уникальным адресом. Принципиальных отличий между static inline и static нет, с той только разницей, что в первом случае дается подсказка компилятору.Ответ 2
это очевидно из самой сути inline -- если код такой функции в самом деле "заинлайнен", то на него существует (логически) только одна ссылка (а именно в том месте, где код "инлайнится"), следовательно никаких проблем с "multiple definition" (т.е. проблемы выбора той или иной точки входа) не существует. тут принципиальное отличие возникает при наличии static переменных у таких (inline и static inline функций. В каждой единице компиляции у static inline будут свои экземпляры таких переменных (а у "не static" один экземпляр static переменной на весь загрузочный модуль (результат линковки)).
Комментариев нет:
Отправить комментарий