Давайте возьмем заголовочный файл var.h
#include <iostream>
class var
{public:
var () {std::cout << "Creating var at " << this << std::endl; }
~var () {std::cout << "Deleting var at " << this << std::endl; }
};
и два исходных файла: первый lib.cpp
#include "var.h"
var A;
и второй app.cpp
#include "var.h"
var A;
int main ()
{return 0;
}
затем, если я попытаюсь скомпилировать их
g++ -c app.cpp
g++ -c lib.cpp
g++ -o app app.o lib.o
компоновщик вернет ошибку с множественными переменными.Но если я скомпилирую его в разделяемую библиотеку + главное приложение
g++ -fPIC -c lib.cpp
g++ --shared -o liblib.so lib.o
g++ -fPIC -c app.cpp
g++ -o app -llib -L . app.o
, он будет ссылаться без ошибок.Однако программа не работает должным образом:
./app
Creating var at 0x6013c0
Creating var at 0x6013c0
Deleting var at 0x6013c0
Deleting var at 0x6013c0
, поэтому разные переменные были созданы по одному адресу памяти!Это может привести к серьезным проблемам, например, в случае, когда библиотека и приложение ожидают, что они будут иметь разные значения (в данном случае значения полей объекта).
, если class var
сделать выделение памяти / удаление valgrind предупреждаето доступе к памяти в недавно удаленном блоке.
Да, я знаю, что мог бы поставить static var A;
вместо var A;
, и оба способа компиляции будут работать правильно.Мой вопрос: почему нельзя использовать одноименные переменные (или даже функции?) В разных библиотеках?Создатели библиотеки могут ничего не знать об именах, которые используют друг друга, и не должны предупреждаться об использовании static
.Почему GNU связанный не предупреждает об этом конфликте?
И, кстати, может dlload
поставить в ту же проблему?
UPD.Спасибо всем за объяснение пространств имен и extern, я понимаю, почему одни и те же символы помещаются в один и тот же адрес памяти, но все еще не могу понять, почему не отображается ошибка связывания или даже предупреждение о дважды определенной переменной, а во втором случае генерируется неправильный код.