К списку форумов К списку вопросов
Прикол с компилятором С
Lexman
15.10.2004 - 19:49
Хотя, вероятнее что прикол у меня в голове, но всё же:
..Создал хедер с глобальными переменными, чтобы иметь доступ к ним из других модулей, просто подключив его.
Использовал приличия ради конструкцию типа
#ifndef _GlobalVars_
#define _GlobalVars_
.... здесь объявляем переменные ....
#endif.
...
Наивно подключаю этот файл в нескольких других модулях и
при компиляции получаю ошибку, что мои переменные объявлены несколько раз (естественно, ссылка на одно и то же место - на этот самый хедер).
Вот такая проблема.
...
Кстати - речь идет об компиляторе CodeVision AVR 1.24 - прогрмамматор для контроллеров.
Тигренок
1 - 15.10.2004 - 20:04
с помошью твоих макросов компилятор включил этот код в каждый объектник по одному разу (а не много раз). соотвестенно в каждом объектнике были объявлены эти переменные. переменные нужно объявить в одном объектнике (C/CPP файле):
int myVar1;
float myVar2;
затем либо в каждом месте, где нужно, писать перед использованием
extern int myVar1;
extern float myVar2;
либо создать *.H-файл, написать это там, и включать его где нужно...
Lexman
2 - 16.10.2004 - 12:12
Собственно, *.Н я и написал (см. выше).
При этом тоже надо extern использовать?
А если этих переменных тысяча? :))
Тигренок
3 - 16.10.2004 - 13:37
значит объявить 1000 переменных в C-файле и 1000 extern'ов для них в H :)
Сергей
4 - 16.10.2004 - 13:48
Перечитай, что пишет Тигренок; тебе необходимо разобраться, как вообще происходит компиляция в С++, из каких стадий состоит, и тогда все станет понятно. Подробное описание этого процесса есть в любой вменяемой книге по языку С++.
Попробую объяснить в двух словах.
Процесс компиляции состоит из нескольких фаз:
   а) обработка кода препроцессором
   б) компиляция единиц трансляции в объектные файлы
   в) линковка объектных файлов в исполняемый модуль (для нас это .exe)
Важно понимать, что сам по себе *.h-файл не компилируется; перед тем, как начать компиляцию, все файлы проекта обрабатываются препроцессором; при этом в текст *.срр полностью (!) и без изменений (!) включаются все *.h-файлы, которые подключены в него директивой #inсludе. Таким образом создаются "единицы трансляции"; они подаются на вход компилятору и компилируются раздельно, независимо друг от друга (принцип раздельной компиляции).
Например, имеем файл prog.h:
int x;
int y;
int z;
И файл prog.cpp:
// program example
#inсludе "prog.h"
int main()
{
  return 0;
}
Тогда для компилятора единица трансляции "prog.cpp" будет выглядеть так:
// program example
int x;
int y;
int z;
int main()
{
  return 0;
}
Соответственно, если prog.h будет включен в десять разных .cpp, то и в них точно также будет включен тот же самый текст из prog.h. Что при этом будет происходить во время компиляции? Так как С++ компилирует единицы трансляции раздельно, то проблем не возникнет - просто в каждый объектный файл будут "физически" включены переменные x,y,z.
Однако проблемы начнутся при линковке - на этом этапе компоновщик (linker) попытается связать вместе все получившиеся на этапе компиляции объектные файлы и выяснит, что в разных файлах имеются дублирующиеся переменные.
Чтобы этого избежать, необходимо размещать переменные только в одной (!) единице трансляции, а в остальных указывать лишь "ссылки" на них. Делается это при помощи директивы extern. Она как раз и сообщает компилятору, что переменная с заданным именем и заданного типа станет доступной на этапе линковки из другой единицы трансляции, а в данной единице трансляции выделять под нее память не нужно.
Таким образом, приведенный выше пример должен выглядеть таким образом:
Файл prog.h:
extern int x;
extern int y;
extern int z;
Файл prog_global_data.cpp
int x;
int y;
int z;
Файл prog.cpp:
#inсludе "prog.h"
int main()
{
  return 0;
}
В данном случае при компиляции получим две единицы трансляции - prog__global_data.cpp и prog.cpp; В первом объектом файле будет присутствовать реализация переменных x,y,z, а во втором, после включения prog.h, будут присутствовать "уведомления" компилятору о том, что переменные x,y,z имеют тип int и будут доступны на этапе линковки.
Все.
Сергей
5 - 16.10.2004 - 13:59
[2] "А если этих переменных тысяча?"
К сожалению, глобальные переменные часто создают серьезные проблемы, особенно в крупных проектах, поэтому ситуация с таким количеством глобальных данных все же редкость.
Lexman
6 - 16.10.2004 - 19:27
Все понятно :), я действительно не С-шник, но примерно так я себе проблему и представлял. Просто мне казалось, что в препроцессоре есть возможность отключить компиляцию части кода с помощью как-л. директив (см. пост 1).
То что с глобальными переменными существуют сложности, это я вкурсе даже на своей шкуре, но вданном случае видимо придется смириться - так как хочется написать не удастся... Придется прописывать extern.
Спасибо за консультацию!

К списку вопросов на форуме Программирование

>>