Можно ли объявить глобальную переменную внутри библиотеки, которая позже скомпилирована в общий объект? Безопасно ли ссылаться на него из других библиотек или основного кода приложения, объявляя его как extern?
В теории это работает:
[[email protected] snippets]$ cat libcode.c
int variable; // <-- this is a global variable declared in a Library
void set_var(int value) {
variable=value;
}
int get_var(void) {
return variable;
}
[[email protected] snippets]$ gcc -g -fPIC -c libcode.c
[[email protected] snippets]$ gcc -o libcode.so -shared libcode.o
[[email protected] snippets]$ cat appcode.c
#include <stdio.h>
// simplified .h declarations:
extern int variable;
void set_var(int value);
int get_var(void);
void main(void) {
set_var(44);
printf("var=%d\n",variable);
variable=33;
int var_copy=get_var();
printf("var_copy=%d\n",var_copy);
}
[[email protected] snippets]$ gcc -g -o app -L./ -lcode appcode.c
[[email protected] snippets]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
[[email protected] snippets]$ ./app
var=44
var_copy=33
[[email protected] snippets]$
Давайте рассмотрим его с помощью отладчика:
[[email protected] snippets]$ gdb ./app
.....
(gdb) break main
Breakpoint 1 at 0x40077e: file appcode.c, line 9.
(gdb) run
Starting program: /home/deptrack/depserv/snippets/app
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.22-16.fc23.x86_64
Breakpoint 1, main () at appcode.c:9
9 set_var(44);
(gdb) print &variable
$1 = (int *) 0x601044 <variable>
(gdb) s
set_var (value=44) at libcode.c:4
4 variable=value;
(gdb) s
5 }
(gdb) s
main () at appcode.c:10
10 printf("var=%d\n",variable);
(gdb) s
var=44
11 variable=33;
(gdb) s
12 int var_copy=get_var();
(gdb) s
get_var () at libcode.c:7
7 return variable;
(gdb) s
8 }
(gdb) s
main () at appcode.c:13
13 printf("var_copy=%d\n",var_copy);
(gdb) s
var_copy=33
14 }
(gdb) s
0x00007ffff7839580 in __libc_start_main () from /lib64/libc.so.6
(gdb) s
Single stepping until exit from function __libc_start_main,
which has no line number information.
[Inferior 1 (process 28380) exited with code 014]
(gdb)
Я говорю "в теории", это работает, потому что, используя этот подход в большом проекте, я столкнулся с ошибкой, где ссылка на такую переменную дала мне неожиданные результаты. Адрес переменной был необычно высоким (0x7ffff767c640), и единственным решением было объявить все глобальные переменные внутри основного кода приложения и использовать "extern" для ссылки на них в коде библиотеки. Однако, таким образом, библиотека не могла иметь переменных самостоятельно. См. Этот вопрос для деталей: получение неправильного адреса переменной во время вызова функции