iAlexander |
Отправлено: 23.09.2003, 17:46 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 70
|
Совсем плохо с мозгами. Объявил в Main.h 'глобальную' переменную Rate, могу присвоить ее в Main.cpp, но при попытке ее копирования в другом модуле ошибки не происходит, но копируется ноль. Хорошо, пример перед глазами. Сделал ее extern double Rate в .h и double Rate в .cpp. Теперь порядок. Но в чем же трабл? |
|
Георгий |
Отправлено: 23.09.2003, 21:37 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
Препроцессор вставляет на место строки #include ... текст файла. Поэтому у тебя в первом случае фактически получилось, что каждый модуль, включивший этот файл заголовков, имеет свою личную переменную Rate.
Объявление переменной как extern в файле заголовков и обычное объявление переменной (могу ошибаться, но класс памяти этой переменной обязан быть static) с этим же именем в одном из файлов проекта приводит к тому, что редактор связей (linker) заменяет все обращения к переменной, для которой в файле есть только объявление extern, на обращения к той переменной имя которой совпадает с именем extern переменной, но не extern.
Примерный аглоритм работы компилятора и редактора связей:
дано:
CODE |
1-й файл:
extern int Rate;
cout<<Rate;
2-й файл:
extern int Rate;
int Rate;
Rate=666;
|
после работы компилятора (пишу на псевдокоде):
1-й файл:
CODE |
call operator<<(ostream&, extern int Rate);
т.е. написан код вызова функции, с аргументом, фактический адрес которого неизвестен
2-й файл:
Rate:=666
т.е. записать в переменную Rate значение (тут никаких неопределённостей нет)
|
работа редактора связей:
CODE |
1-й и 2-й файлы фактически объединяются, после чего выполняется разрешение меток:
extern int Rate заменяется на адрес int Rate,
operator<<(ostream&, int Rate) заменяется на адрес библиотечной функции.
|
PS. С этим линкером у меня связана одна история:
Однажды наткнулся на глюк в BCB 5pro : в 2-х модулях были внутримодульные функции, прототип которых был полностью одинаков. В результате в конечном коде оказывалать только одна из них вместо 2-х, а у меня чуть волосы дыбом не стали — представьте себе вызывается функция с пустым телом ( int asd(void){return 0;} ), а значение она далеко не нулевое возвращает!!! Полтергейст блин!
Отредактировано Георгий — 23/09/2003, 22:41 |
|
Jean |
Отправлено: 23.09.2003, 21:54 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 34
|
Хотя есть и плюс в таком подходе: у меня в каждом модуле есть функции, которые нужны для работы модуля, что-то вроде
CODE |
void QueryOpen(TQuery *Query, AnsiString sSQL)
{
Query->Close();
Query->SQL->Text = sSQL;
Query->Open();
}
|
И долгое время я копировал их в каждый модуль. А недавно обнаружилось, что в модулях, кроме главного, необходимо вставить лишь объявление этих функций. Потому как они все равно выполняются в главном модуле
Обнаружилось при отладке — при обращении к функции, он лезет в главный модуль, хотя в данном присутствует аналогичная функция.
|
|
Георгий |
Отправлено: 24.09.2003, 09:22 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
Счастливчик — у тебя хоть код всех этих функций был одинаковый (по крайней меря я так понял), а у меня совершенно случайно 2 разных функции (они вызывались из одного моего обьекта для обработки данных — что-то вроде bsearch, qsort) были названы одинаково, но выполняли принципиально разные действия. И представляешь моё удивление, когда функция (алгоритм работы которой прост как программа Hello World) стала работать не правильно, а ещё больше я удивился, когда весь код этой функции заремил, а она продолжала работать, да и с той же ошибкой! Я такого никогда раньше не видел — пустая функция, а работает! Хорошо, что догадался, посмотреть, чтоже за функция вызывается вместо той, что была нужна. |
|
|