74 / 37 / 3
Регистрация: 23.09.2012
Сообщений: 408
|
||||||
1 | ||||||
Как правильно из одного cpp подключить другой06.10.2012, 00:02. Показов 12831. Ответов 34
Метки нет (Все метки)
Есть 2 .cpp файла: a.cpp и b.cpp. Когда пишу:
0
|
06.10.2012, 00:02 | |
Ответы с готовыми решениями:
34
Перенос данных из одного cpp в другой Передать значения переменных из одного cpp в другой Как правильно подключить два винчестера(один sata, другой ide)? Как правильно перенести сайт с одного хостинга на другой? |
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
|
|||||||||||||||||||||
07.10.2012, 21:50 | 21 | ||||||||||||||||||||
Сообщение было отмечено как решение
Решение
func.h
Клюс -c говорит, что необходимо остановится сразу после генерации объектного кода, а не вызывать линкёр и генерировать бинарный файл. В первой строке отдельно компилируется файл func.cpp, на выходе будет объектный файл func.o. Здесь компилятору неважно, что эта функция где-то вызывается. Ему вообще не важно, вызывается она или нет. Его просят откомпилировать исходный файл в объектный, и он это делает. Во второй строке отдельно компилируется файл main.cpp, на выходе объектный файл main.o. Компилятор при встрече вызова функции, определения которой не видит, вместо кода вызова этой функции (в котором фигурирует адрес, по которому она располагается в исполняемом файле) поставит заглушку, содержащую всю необходимую информацию, по которой линкёр сможет заглушку эту изменить на реальный адрес вызываемой функции (важно, чтобы он не ошибся и не подставил туда какой-то другой адрес, поэтому и нужна информативная заглушка). Всё, больше компилятору ничего не нужно, он не хочет видеть здесь тело функции, а возлагает поиск этого тела на линкёр. В третьей строке, хотя и вызывается компилятор g++, на самом деле он сразу же вызовет линкёр (утилита ld), который сделает следующее (в неформальном виде, только для общего понимания процесса): отыщет все заглушки, поставленные компилятором, расшифрует информацию, которая в них хранится, найдёт в других объектных файлах реализации функций, соответствующих заглушкам, и заменит заглушки на код вызовов этих функций. В случае, если реализации какой-либо функции найдено не будет - линкёр выдаст ошибку о неразрешённой внешней ссылке. В случае множественного определения также будет выдана ошибка. Именно из-за всего, написанного выше, линкёру и нужно передавать ВСЕ объектные модули, которые ранее компилировались по-отдельности, ведь линкёр должен располагать всеми адресами всех используемых функций.
4
|
74 / 37 / 3
Регистрация: 23.09.2012
Сообщений: 408
|
|
07.10.2012, 21:53 [ТС] | 22 |
alsav22, хм, вы правы. Попробовал - почти все прояснилось. Единственное:
Я правильно понимаю, что если есть некий заголовочный файл, в нем прототипы функций, то компилятор полезет в точно так же названный cpp файл за этими функциями?
0
|
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
|
|
07.10.2012, 22:03 | 23 |
Нет, так он делать не будет. Прочтите моё сообщение, там есть очень важный вывод (в явном виде, правда, не оформленный): во-первых, вызов компилятора заключается в неявном вызове кучи различных вспомогательных утилит (препроцессор, лексический анализатор, синтаксический анализатор, редактор связей и много чего ещё). Во-вторых, важно понимать, что все эти утилиты распределяют обязанности между собой. Компилятор не занимается линковкой, а линкёр - компиляцией. У каждого свои задачи, требующие своей входной информации.
0
|
74 / 37 / 3
Регистрация: 23.09.2012
Сообщений: 408
|
|
07.10.2012, 22:03 [ТС] | 24 |
silent_1991, хм. Не совсем понимаю смысл создавать отдельный cpp, если потом в него включается .h. Ведь есть в хедере изменить хоть 1 несущественный символ, компилировать придется заново. Разве это не сводит всю прелесть на нет?
Так же, не понимаю, разве двойное включение <iostream> не сделает хуже? ведь оба файла компилируются отдельно. И получается в обоих .o будет код из iostream
0
|
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
|
|
07.10.2012, 22:06 | 25 |
Теоретически да. Практически же реализацию редактировать придётся куда чаще, чем объявление. Хедер будет редактироваться только в связи с какими-либо значительными изменениями (введение нового пользовательского типа, новой функции, изменение тела класса и т.д.), который в любом случае повлекут за собой перекомпиляцию реализации, в которой также необходимо отслеживать эти изменения и поддерживать их в актуальном состоянии.
0
|
74 / 37 / 3
Регистрация: 23.09.2012
Сообщений: 408
|
|
07.10.2012, 22:09 [ТС] | 26 |
silent_1991, а как линкер поймет, из какого файла брать реализацию?
0
|
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
|
|
07.10.2012, 22:11 | 27 |
Kgfq, ну ведь на момент вызова у него есть вся необходимая информация, все файлы с реализацией ему предоставлены. Здесь в ход вступает такая вещь, как таблица символов, которая является, по сути, индексом всего содержимого объектного файла. Если линкёр находит в таблице символов символ, соответствующий разрешаемой им в данный момент заглушке, он берёт из этой таблицы смещение и подставляет его вместо заглушки.
Возможно, я несколько не точен в деталях реализации, но концепция такая.
0
|
74 / 37 / 3
Регистрация: 23.09.2012
Сообщений: 408
|
|
07.10.2012, 22:22 [ТС] | 29 |
alsav22, как я себе представлял это - реализация должна абстрагироваться от остального кода.
Какая разница, какие классы есть в коде, когда этой функции нужно подать определенное значение и она должна его как-то изменить.
0
|
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
|
|
07.10.2012, 22:32 | 30 |
Kgfq, так она и абстрагирована. Возьмите мой пример. В main.cpp абсолютно ничего неизвестно о реализации func. Всё это дело склеивается в единый монолит на самой последней стадии - стадии линковки.
0
|
74 / 37 / 3
Регистрация: 23.09.2012
Сообщений: 408
|
|
07.10.2012, 23:05 [ТС] | 32 |
silent_1991,
alsav22, Спасибо за подробные объяснения, я разобрался. Единственное, еще вопрос, когда стоит начинать задумываться о разделении прототипа и реализации?
0
|
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
|
|
07.10.2012, 23:14 | 33 |
К правильному, желательно, сразу привыкать. Неверное, есть смысл помещать прототипы отдельно, в заголовочном файле, когда много функций и они используются во многих файлах.
Добавлено через 4 минуты Стоит сказать ещё о шаблонах. Прототип шаблона и реализация должны быть в одном файле.
1
|
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
|
|
08.10.2012, 01:12 | 34 |
Kgfq, задумываться стоит сразу. Ещё почитайте о системах сборки, например, make. Именно с ними все прелести раздельной компиляции показываются наружу.
На счёт шаблонов: иными словами, шаблон - единственный случай, когда подключается не объявление, а полностью реализация. Такова особенность шаблонов.
0
|
36 / 36 / 0
Регистрация: 09.08.2012
Сообщений: 132
|
||||||||||||||||
08.10.2012, 04:50 | 35 | |||||||||||||||
func.h
0
|
08.10.2012, 04:50 | |
08.10.2012, 04:50 | |
Помогаю со студенческими работами здесь
35
Как правильно передать метод делегата из одного класса в другой? Как ПРАВИЛЬНО перенести windows 7 с одного компьютера на другой через образ? Как подключить cpp-файл к h-файлу? Как подключить элементы из cpp файла? Как подключить cpp файл к проекту? Как подключить библиотеку OpenGL к файлу .cpp Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |