Форум программистов, компьютерный форум CyberForum.ru

Как правильно из одного cpp подключить другой - C++

Восстановить пароль Регистрация
Другие темы раздела
C++ Составить описание класса прямоугольников со сторонами, параллельными осям координат http://www.cyberforum.ru/cpp-beginners/thread664391.html
Составить описание класса прямоугольников со сторонами, параллельными осям координат. Предусмотреть возможность перемещения прямоугольников на плоскости, изменения размеров, построения наименьшего прямоугольника, который содержит два заданы прямоугольники, и прямоугольника, являющегося общей частью (пересечением) двух прямоугольников. Написать программу, демонстрирующую работу с этим классом....
C++ Построение геометрической фигуры Извините, что за вечер прошу у вас помощи несколько раз. Думал справлюсь, но, увы. первый файл - это то, что нужно сделать. есть код для примера #include <vcl.h> #include <iostream.h> #include <iomanip.h> #include <conio.h> void main() { int n=18 ; cout<<'*'<<endl ; http://www.cyberforum.ru/cpp-beginners/thread664383.html
C++ Библиотека полиномов
Всем привет,я создал библиотеку для работы с полиномами(сложение,вычитание,дифф. итд) но прога не работает,когда один из полиномов нулевой степени мне кажется,что ошибка вот в этой процедуре polinom *SummaPolinomov(polinom *a,polinom*b) { polinom *c=new polinom; if(a->stepen_m>=b->stepen_m) {
C++ Интерпретатор небольшого языка программирования на С++
Здравствуйте, уважаемые форумчане! Я тут где-то год назад прочитал тему Evg и #pragma о создании интерпретатора, меня эта тема очень заинтересовала. Я изучаю книги, читаю статьи по разработке компиляторов и интерпретаторов. В этой теме хочу описать свой небольшой математический язык программирования(назв. - MatLang) и интерпретатор для него, написанный на C++. Язык MatLang - интерпретируемый...
C++ Работа с random http://www.cyberforum.ru/cpp-beginners/thread664369.html
Доброго времени суток! У меня есть массив int a={10,20,30,40,50}. Можно сделать так, чтобы выводились эти числа рандомом и не повторялись??? Я сделал так ну что-то не то((( #include<conio.h> #include<iostream.h> #include<stdlib.h> void main () { clrscr ();
C++ bool при чтении из файла задание такое Сделайте функцию чтения из файла такой, чтобы она возвращала bool (истина - если считали данные, ложь - если нет) и добавьте проверку этого возвращаемого значения в main. собственно код void read_file(void) { FILE* file = fopen("arr.txt", "r"); подробнее

Показать сообщение отдельно
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
07.10.2012, 21:50     Как правильно из одного cpp подключить другой
func.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Следующая конструкция ifndef-define-endif имеет название "страж включения".
// Она нужна для предотвращения множественного включения одного и того же файла
// в другой файл. Суть работы следующая: при первом включении файла с помощью
// define символ FUNC_H (или любой другой, главное, чтобы он был по возможности
// уникальным и совпадал в ifndef и define) ещё не определён; препроцессор
// определяет этот символ и включает весь текст, который находится между ifndef
// и endif. При повторном включении файла символ FUNC_H будет ужё определён, и
// препроцессор уже не будет включать текст, находяцийся между ifndef и endif
#ifndef FUNC_H
#define FUNC_H
 
// Прототип функции. Говорит компилятору, что эту функцию можно вызвать с двумя
// аргументами типов double и char соответственно (или совместимых с ними), а
// также, возможно, присвоить её результат переменной типа int (или совместимого
// с ним)
int func(double d, char c);
 
#endif // FUNC_H
func.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// В данном случае подключение этого заголовочного файла не обязательно,
// поскольку ничего нового компилятору он не скажет. В общем случае, когда в
// заголовочном файле определяется больше информации (например, какие-то
// пользовательские типы и т.д.), которая используется в данном файле
// реализации, подключить этот файл необходимо. Я обычно всегда подключаю
// заголовочный файл в файле реалиации, это позволяет связать эти два файла в
// единый модуль (позволяет связать программисту, а не компилятору)
#include "func.h"
 
// Здесь всё стандартно, подключаем заголовочные файлы, функции из которых будем
// использовать в файле реализации
#include <iostream>
 
// Реализация функции, объявленной в заголовочном файле
int func(double d, char c)
{
    // Выводим на экран значения переданных в функцию аргументов
    std::cout << "double d = " << d << "; char c = " << c << std::endl;
    
    // Возвращаем из функции ASCII-код второго аргумента; приведение типа
    // здесь необязательно, но явное лучше, чем неявное
    return static_cast<int>(c);
}
main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Файл, в котором используется функция, объявленная в func.h и реализованная в
// func.cpp
#include <iostream>
 
// Смысл включения здесь этого файла в следующем: когда компилятор встрети вызов
// func, ему не обязательно знать, как эта функция реализована; нужно только
// знать, аргументы каких типов можно в неё передавать и значение какого типа
// она возвращает. В этом ему поможет прототип функции.
// По факту препроцессор, который вызывается ещё ДО компиляции, просто подставит
// вместо этого оператора всё, что в файле func.h располагается между ifndef
// и endif. Т.е. вместо
// 
// #include "func.h"
// 
// будет текстово подставлено
//
// #define FUNC_H
//
// int func(double d, char c);
// 
#include "func.h"
 
int main()
{
    double d = 3.14;
    char c = 'X';
    
    // Здесь происходит вызов функции func. При этом тело этой функции
    // компилятору видеть ненужно, ведь на стадии компиляции ещё нет никакого
    // вызова функции, есть только код, который этот вызов осуществляет. Здесь
    // компилятор проверит (на основании прототипа, который уже был текстово
    // включён в данный файл препроцессором), подходят ли типы аргументов,
    // передаваемых в функцию (если необходимо преобразование и компиилятор
    // может выполнить его автоматически, перед вызовом будет подставлен код,
    // выполняющий преобразование), а также можно ли результат функции присвоить
    // переменной того типа, которой он присваивается (опять же, если необходимо
    // преобразование - оно будет по возможности выполнено перед сохранение
    // результата в соответствующую переменную)
    int result = func(d, c);
    
    std::cout << result << std::endl;
    
    return 0;
}
Компиляция:
Bash
1
2
3
g++ -ansi -Wall -c -o func.o func.cpp
g++ -ansi -Wall -c -o main.o main.cpp
g++ -o main func.o main.o
Ключ -ansi говорит компилятору не делать никаких поблажек и строжайшим образом отыскивать все несоответствия стандарту. Ключ -Wall запрещает подавлять какие-либо, даже несущественные, предупреждения, и сообщать обо всём, что он посчитал хоть сколько нибудь неверным. Можно было бы обойтись и без них, но я так привык.
Клюс -c говорит, что необходимо остановится сразу после генерации объектного кода, а не вызывать линкёр и генерировать бинарный файл.
В первой строке отдельно компилируется файл func.cpp, на выходе будет объектный файл func.o. Здесь компилятору неважно, что эта функция где-то вызывается. Ему вообще не важно, вызывается она или нет. Его просят откомпилировать исходный файл в объектный, и он это делает.
Во второй строке отдельно компилируется файл main.cpp, на выходе объектный файл main.o. Компилятор при встрече вызова функции, определения которой не видит, вместо кода вызова этой функции (в котором фигурирует адрес, по которому она располагается в исполняемом файле) поставит заглушку, содержащую всю необходимую информацию, по которой линкёр сможет заглушку эту изменить на реальный адрес вызываемой функции (важно, чтобы он не ошибся и не подставил туда какой-то другой адрес, поэтому и нужна информативная заглушка). Всё, больше компилятору ничего не нужно, он не хочет видеть здесь тело функции, а возлагает поиск этого тела на линкёр.
В третьей строке, хотя и вызывается компилятор g++, на самом деле он сразу же вызовет линкёр (утилита ld), который сделает следующее (в неформальном виде, только для общего понимания процесса): отыщет все заглушки, поставленные компилятором, расшифрует информацию, которая в них хранится, найдёт в других объектных файлах реализации функций, соответствующих заглушкам, и заменит заглушки на код вызовов этих функций. В случае, если реализации какой-либо функции найдено не будет - линкёр выдаст ошибку о неразрешённой внешней ссылке. В случае множественного определения также будет выдана ошибка. Именно из-за всего, написанного выше, линкёру и нужно передавать ВСЕ объектные модули, которые ранее компилировались по-отдельности, ведь линкёр должен располагать всеми адресами всех используемых функций.
 
Текущее время: 21:33. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru