2010-02-11 2 views
3

Я работаю над получением rLog для создания DLL под окнами, и я получал неопределенные ошибки символов, связанные с некоторыми глобальными символами в пространстве имен rlog. В частности они в RLogChannel.cpp:Как правильно использовать extern в пространстве имен?

namespace rlog { 
... 
    RLogChannel *_RLDebugChannel = GetGlobalChannel("debug", Log_Debug); 
    RLogChannel *_RLInfoChannel = GetGlobalChannel("info", Log_Info); 
    RLogChannel *_RLWarningChannel = GetGlobalChannel("warning", Log_Warning); 
    RLogChannel *_RLErrorChannel = GetGlobalChannel("error", Log_Error); 
... 
}; 

Я предположил, проблема в том, что 1) они не были экспортированы и 2) они не были объявлены в заголовке, так что другие вещи могут получить доступ к ним. Поэтому я добавил __declspec (dllexport) (с помощью макроса RLOG_DECL) к ним, а также в заголовке, говоря:

namespace rlog { 
... 
    RLOG_DECL extern RLogChannel *_RLDebugChannel; 
    RLOG_DECL extern RLogChannel *_RLInfoChannel; 
    RLOG_DECL extern RLogChannel *_RLWarningChannel; 
    RLOG_DECL extern RLogChannel *_RLErrorChannel; 
... 
}; 

Но независимо от того, как я объявляю переменные в RLogChannel.cpp я получаю ошибку переопределение, несмотря на мой externing их в заголовке ... Каков правильный способ сделать это? Похоже, это должно быть просто, но я не могу полностью обвести вокруг себя голову.

Edit: сообщение об ошибке

Error 12 error C2086: 'rlog::RLogChannel *rlog::_RLDebugChannel' : redefinition rlog-1.4\rlog\RLogChannel.cpp 45 rlog 

(то же самое для всех 4-х символов)

Edit: я не знаю, что случилось, код точно так же, и раньше, но теперь он будет компилировать (чувствует как странность MSVC ...), к сожалению, символы по-прежнему отображаются как неразрешенные при подключении к моей библиотеке

+1

что точное сообщение об ошибке –

+0

Обновлено выше, так что отформатирован немного лучше, чем я? можно отправить здесь. –

+0

Кажется, что-то importa nt не учитывается. Можете ли вы предоставить краткий и полный тестовый пример (например, один файл, который я могу передать компилятору как есть), который дает эту ошибку? – 2010-02-11 22:07:55

ответ

1

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

Решение этого. Предполагая, что файлы называются rlog.c & rlog.h

--- (rlog.h) --- 
#ifdef RLOG_DEFINES 
#define EXTERN 
#else 
#define EXTERN extern 
#endif 


namespace rlog { 
... 
    RLOG_DECL EXTERN RLogChannel *_RLDebugChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLInfoChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLWarningChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLErrorChannel; 
... 
}; 


--- (rlog.c) --- 
#define RLOG_DEFINES 
#include "rlog.h" 

... 

--- (other .c files) --- 
#include "rlog.h" 

Красота этого решения заключается в том, что, поскольку эти определения определены только один раз в проекте, вы никогда не получите их из синхронизации друг с другом и вам нужно только изменить их в одном месте. Представьте, если вы определили переменную как длинную, но в определении extern она была объявлена ​​как короткая? вы можете столкнуться с неожиданными побочными эффектами. Таким образом, это помогает предотвратить эти проблемы.

Надеюсь, что это поможет.

+0

Он уже сказал, что определил их один раз в файле cpp и объявил их в заголовке. – Potatoswatter

+0

Я все еще получаю несколько ошибок определения, когда я делаю это, к сожалению ... –

+0

Обычное решение для определения их в .c файле также означает, что они только когда-либо определены один раз в проекте. Включение заголовка из этого файла (с декларациями) гарантирует, что у вас нет случайных несоответствий, поскольку компилятор будет давать ошибки, если вы это сделаете. Короче говоря, я не вижу преимуществ в коде, который вы даете, но у него есть недостатки, связанные с тем, что они сложнее и не соответствуют нормальному соглашению. – 2010-02-11 22:03:27

1

Я думаю, что Мэтт довольно близко. Я столкнулась с этой проблемой некоторое время идти и правильный (и большинство портативных решений заключается в следующем:

--- (rlog.h) --- 
#ifdef RLOG_DEFINES 
#define RLOG_DECL __declspec(dllexport) 
#else 
#define RLOG_DECL __declspec(dllimport) 
#endif 


namespace rlog { 
... 
    RLOG_DECL extern RLogChannel *_RLDebugChannel; 
    RLOG_DECL extern RLogChannel *_RLInfoChannel; 
    RLOG_DECL extern RLogChannel *_RLWarningChannel; 
    RLOG_DECL extern RLogChannel *_RLErrorChannel; 
... 
}; 


--- (rlog.c) --- 
#define RLOG_DEFINES 
#include "rlog.h" 

namespace rlog { 
... 
    __declspec(dllexport) RLogChannel *_RLDebugChannel = GetGlobalChannel("debug", Log_Debug); 
    __declspec(dllexport) RLogChannel *_RLInfoChannel = GetGlobalChannel("info", Log_Info); 
    __declspec(dllexport) RLogChannel *_RLWarningChannel = GetGlobalChannel("warning", Log_Warning); 
    __declspec(dllexport) RLogChannel *_RLErrorChannel = GetGlobalChannel("error", Log_Error); 
... 
}; 


--- (other .c files) --- 
#include "rlog.h" 

Правило простое При компиляции DLL, которая обеспечивает dllexport должны быть согласованы как в декларации символа и определения.. с другой стороны, когда внешний мир использует вашу библиотеку. - она ​​должна появиться к нему как DllImport символ

с уважением, Maciej Яблонски

Смежные вопросы