Ответ 1
Общие библиотеки не являются концепцией C. Разделенные библиотеки различных операционных систем и вычислительных платформ, где они существуют, демонстрируют различия в форме и поведении.
Тем не менее, да, все распространенные реализации библиотек, о которых я знаю, поддерживают переменные с точки зрения C, статической продолжительности хранения и внешней связи, которые, как я предполагаю, вы понимаете под "глобальными". Поскольку вы, кажется, используете Linux, ваши общие библиотеки будут иметь аромат ELF. В этом случае каждый процесс, который динамически связывает общую библиотеку, получит свою собственную копию таких переменных.
Большой адрес переменной, который вы описываете, не имеет особого значения. Общие библиотеки ELF не должны загружаться по какому-либо конкретному адресу, и на самом деле Linux реализует ASLR, который активно меняет адреса загрузки библиотеки. Ваша разделяемая библиотека может быть загружена более или менее в любом месте в 64-разрядном виртуальном адресном пространстве вашей системы, поэтому вы действительно не можете много узнать о том, что адрес переменной численно большой.
Что касается описанной вами ошибки, я склонен думать, что она возникла из-за плохого кода, а не (напрямую) от участия в общей библиотеке. Из вашего описания, я подозреваю, что вы оказались с несколькими переменными с тем же именем, все с внешней связью. Это ошибка со статической привязкой, но в этом случае компилятор может (и по умолчанию, GCC) объединять повторяющиеся переменные вместо отказа от кода.
С ELF, с другой стороны, это нормально для того же символа, который должен быть определен в нескольких общих объектах, связанных с одним и тем же процессом, и различные определения могут ссылаться на разные точки в общем процессе. Поскольку общая библиотека скомпилирована отдельно от основной программы, компилятор не имеет возможности объединять символы, и не очевидно, что это должно даже если бы это было возможно. Но множественные объявления данного символа - возможность не необходимость. Если это произойдет, возможно, потому, что ваши заголовки ошибочно объявляют переменную.
В программе может быть много объявлений любой заданной переменной, но должно быть точно одно определение. Объявления обычно поступают из файла заголовка, и они должны выглядеть следующим образом:
extern int foo;
extern
обязательный, если заголовок должен использоваться в более чем одном исходном файле - это и отсутствие инициализатора устанавливают, что объявление не может быть интерпретировано как определение. Тогда должно быть определение переменной только в одном исходном файле, выглядя примерно так:
int foo = 0;
Наличие инициализатора устанавливает, что объявление также является определением. Это может быть определение, если инициализатор был опущен до тех пор, пока квалификатор extern
не будет включен, но если вы не хотите изучать все детали, тогда безопасно просто предоставить инициализатор.
Проблема, которую вы описываете, возникнет, если в нескольких общих объектах есть определения foo
. Это произойдет, если, например, файл заголовка содержит объявление любой из этих форм:
bad.h
int foo; /* WRONG - without extern, this is a tentative definition */
extern int bar = 0; /* WRONG - because of the initializer, this is a definition */