在 C 程序中,调用动态链接库(Linux 上为共享库或 `.so`,Windows 上为 `.dll`)时,变量的处理取决于变量在库中的定义方式和库的加载方式。
In C programs, when calling a dynamic library (shared library or `.so` on Linux, `.dll` on Windows), the handling of variables depends on how they are defined within the library and how the library is loaded.
1. 库中的全局变量:
如果动态链接库定义了全局变量,那么无论在同一进程中加载或调用多少次动态链接库,每个进程通常只有一个全局变量实例。
- 当同一进程的多个部分(如多个模块或库)链接到共享库时,它们都会共享库中的相同全局变量。
1. Global Variables in the Library:
If the dynamic library defines global variables, there is usually only one instance of those variables per process, no matter how many times the library is loaded or called within the same process.
- When multiple parts of the same process (e.g., multiple modules or libraries) link against a shared library, they all share the same global variables from the library.
2. 静态变量:
如果程序库使用静态变量(函数级或文件级),那么这些变量在加载程序库的进程中只有一个实例。这些变量在该进程内的所有函数调用中共享。
2. Static Variables:
If the library uses static variables (either function-level or file-level), there is only one instance of these variables for the lifetime of the process that loads the library. These are shared across all function calls within that process.
3. 线程本地存储:
如果动态链接库使用线程本地存储(TLS)(例如 GCC 中的 `__thread` 关键字或 C11 中的 `_Thread_local`),那么每个线程都将拥有自己的变量实例。这允许同一进程中的不同线程拥有独立的变量实例。
3. Thread-local Storage:
If the dynamic library is using thread-local storage (TLS) (e.g., with `__thread` keyword in GCC or `_Thread_local` in C11), then each thread will have its own instance of the variable. This allows different threads in the same process to have independent instances of the variable.
4. 动态分配(堆):
如果函数库动态分配内存(例如使用 `malloc`),则每次调用分配内存的函数时,都会获得所分配内存的实例。
4. Dynamic Allocation (Heap):
If the library dynamically allocates memory (e.g., with `malloc`), each call to a function that allocates memory will get its own instance of the allocated memory.
5. 多个进程加载同一个库:
如果多个进程加载同一个动态链接库,每个进程都会有自己的变量实例,甚至是全局变量或静态变量,因为每个进程都有自己的内存空间。
5. Multiple Processes Loading the Same Library:
If multiple processes load the same dynamic library, each process will have its own instance of the variables, even global or static variables, since each process has its own memory space.
总之,对于调用动态链接库的 C 程序而言:
- 全局变量和静态变量在进程内共享。
- 线程本地变量在每个线程中都有独立的实例。
- 动态分配的变量在每次分配时都有单独的实例。
In summary, for a C program calling a dynamic library:
- Global and static variables are shared within a process.
- Thread-local variables have separate instances per thread.
- Dynamically allocated variables have separate instances for each allocation.
举例说明
以errno在glibc中的定义为例,在errno.h头文件种说明如下:
/* The dynamic linker uses its own private errno variable.
All access to errno inside the dynamic linker is serialized,
so a single (hidden) global variable is all it needs. */
就是说,在动态链接库里,errno是一个全局唯一实例,而不是thread变量。
extern int rtld_errno attribute_hidden;
而如果不是在动态库中,其声明就是thread变量。
extern __thread int errno attribute_tls_model_ie;