проблемы с глобальными переменными в проекте разделяемой библиотеки (C ++) - PullRequest
3 голосов
/ 24 августа 2009

У меня проблема с глобальными переменными в проекте совместно используемой библиотеки c ++. Моя библиотека должна работать как стандартная общая библиотека g ++ (.so), а также как dll. я сделал это, создав файлы libiup_dll.cpp и libiup_dll.h, где у меня есть что-то вроде

#ifdef BUILD_DLL

// code for the dll: wrapper functions around the classes in my shared library

#endif

в моей DLL, мне нужны функции setloglevel (int) и geterrormsg (). во всех моих классах я бы добавил к глобальной переменной errormsg все сообщения об ошибках. эта переменная должна затем быть возвращена функцией geterrormsg (). я реализовал это с помощью

std::string errormsg;
int loglevel;

в libiup_dll.h (снаружи и #ifdefs, поэтому он должен быть доступен глобально), а затем поместите

extern std::string errormsg;
extern int loglevel;

в файлах моих классов .h (вне класса, вверху файлов)

теперь у меня две проблемы:

1) при компиляции программы командной строки с g ++, которая использует мою библиотеку, я получаю ошибки

Построение цели: libiup_test Вызов: GCC C ++ Linker G ++ -L "/ home / hilboll / src / libiup / Release" -L / usr / local / lib -o "libiup_test" ./src/stratcalc/SimpleStratosphericColumnCalculatorTest.o ./src/interp/SimpleInterpolatorTest.o ./src/Test.o -lgsl -lhdf5 -lhdf5_cpp -lblas -liup /home/hilboll/src/libiup/Release/libiup.so: неопределенная ссылка на loglevel' /home/hilboll/src/libiup/Release/libiup.so: undefined reference to errormsg ' collect2: ld вернул 1 статус выхода make: *** [libiup_test] Ошибка 1

, хотя в моей программе командной строки нет никаких ссылок на errormsg или loglevel.

2) при попытке скомпилировать dll под windows с VS2008, я получаю

г: \ SRC \ против \ libiup_dll \ libiup_dll.h (229) : ошибка C2086: 'std :: string errormsg': Neudefinition г: \ SRC \ libiup \ SRC \ stratcalc ../ интерполяция / SimpleInterpolator.h (16): Siehe Deklaration von 'errormsg' г: \ SRC \ против \ libiup_dll \ libiup_dll.h (234) : ошибка C2086: 'int loglevel': Neudefinition г: \ SRC \ libiup \ SRC \ stratcalc ../ интерполяция / SimpleInterpolator.h (17): Siehe Deklaration von 'loglevel'

Насколько я понимаю, это означает, что VS считает, что я определяю две переменные дважды. однако в SimpleInterpolator.h 16/17 есть только внешние объявления ...

кажется, я как-то еще не понял, как работают глобальные переменные. любая помощь с благодарностью!

Ответы [ 4 ]

3 голосов
/ 24 августа 2009

Глобалы могут быть объявлены много раз, но должны определяться только один раз.

Ключевое слово "extern" помечает то, что иначе было бы определением как объявление.

Общая идиома того, как вы это делаете, выглядит следующим образом:

// In a header file (declaration)
extern int myGlobal;

// In a source file (definition)
int myGlobal;

Затем, если вы хотите сослаться на глобальное, вы должны либо повторить объявление extern, либо включить заголовочный файл, который уже имеет объявление extern.

Что вы должны абсолютно не сделать, это поместить "int myGlobal" определение (без 'extern') в заголовок. Если вы сделаете это, то каждый файл, содержащий этот заголовок, попытается определить свой собственный myGlobal, и вы получите конфликт символов при ссылке. Определение должно быть в одном и только одном исходном файле. Объявление extern может отображаться в любом количестве файлов или заголовков.

В частности, то, что происходит с вашими двумя ошибками, таково:

  • Когда вы компилируете под Linux, заголовок DLL, который определяет глобальные переменные, удаляется вашими макросами препроцессора, поэтому ваши глобальные переменные имеют объявление, но не имеют определения, и компоновщик жалуется.
  • Когда вы компилируете под Windows, заголовок DLL включается в более чем один модуль компиляции (исходный файл), поэтому глобальные переменные имеют более одного определения, и компоновщик жалуется.
2 голосов
/ 24 августа 2009

Хитрость заключается в том, чтобы знать, что каждый файл .cpp представляет собой единицу компиляции - то есть вещи, которые компилируются. Каждый из них полностью индивидуален и ничего не знает друг о друге. Только на этапе соединения они объединяются.

Теперь extern говорит «эту переменную можно найти в другом месте» для скомпилированного файла cpp, компилятор просто указывает на ссылку компоновщику, чтобы разобраться.

Итак, когда вы поместили определения переменных в файл заголовка, скорее всего, вы включили этот заголовок в 2 (или более) файла cpp. Таким образом, каждый из этих файлов cpp при компиляции думает, что у них есть настоящая переменная. Затем появляется компоновщик и видит слишком много.

Поместите переменные в собственный cpp-файл (или в основной cpp-файл) и вставляйте только внешние ссылки в заголовочные файлы. Тогда вы должны быть в порядке с множественными символами.

0 голосов
/ 24 августа 2009

Вы сказали,

I implemented this by using

    std::string errormsg;
    int loglevel;

in libiup_dll.h (outside and #ifdefs, so it should be globally available),
and then putting

    extern std::string errormsg;
    extern int loglevel;

in my classes' .h files (outside the class, at the top of the files)

Вместо этого я думаю, что вы должны объявить переменные, используя extern в любом количестве заголовочных файлов, а затем определить переменные без extern в одном-единственном C или файл CPP.

0 голосов
/ 24 августа 2009

Вы говорите, что имеете:

std::string errormsg;
int loglevel;

в libiup_dll.h вне любого #ifdefs. Это проблема, если libiup_dll.h включено несколько раз (прямо или косвенно) и, вероятно, является причиной вашей проблемы # 2.

Я думаю, что это также может быть причиной проблемы # 1, если заголовок включен - у вас есть определения переменных, введенных заголовком, даже если вы не можете использовать их в другом месте.

Определение этих двух переменных обычно должно быть в файле .c или .cpp, а не в заголовке. Наличие в заголовке объявления extern нормально в заголовке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...