For some bad ideas about strong symbols, weak symbols, strong references, and weak references in C language, please correct them.
First of all, I am very tragic. I did not know that C has strong symbols, weak symbols, strong references, and weak references before I read "Programmer self-cultivation-links, loading and libraries. I felt a little confused when I saw weak and strong symbols in section 3.5.5. So I wrote this article, hoping to communicate with friends who felt the same and hope to give advice to others. First, let's take a look at their definitions in the book. Introduction scenario: (1) Define and initialize the variable I (int I = 1) in file A, define and initialize the variable I (int I = 2) in file B ). B. o :(. data + 0x0): multiple definition of 'I';. o :(. data + 0x0): multiple definition of 'I '. (2) Define and initialize two variables I (int I = 1; int I = 2) in file C. c. c: 2: 5: error: redefinition of 'I'; c. c: 1: 5: note: previous definition of 'I' was here. Strong Symbol: a symbolic definition like this in a scenario is called a strong symbol. For C/C ++, the default function of the compiler and the initialized global variable are strong symbols. Weak Symbol: link, which indicates that the initialized global variable is a weak symbol. Compiler rules on strong and weak symbols: (1) strong symbols cannot be defined many times, but strong and weak symbols can coexist; (2) Strong coverage is weak when strong and weak symbols coexist; (3) when all are weak symbols, select the largest space occupied. For example, select double type instead of int type. From the above definition, I did not think of the scenario: Code. c: 1 int I = 2; code B. c: copy the Code # include <stdio. h> int I; int main (int argc, char ** argv) {printf ("I = % d \ n", I); return 0 ;} copy the code to compile the files a and B and link them. The result output is 2 instead of 0. In addition, if two variables are defined in the same file but not initialized, no error is reported. Only when variables are used will an error be reported. For the GCC compiler, _ attribute _ (weak) can also be used to define a strong symbol as a weak symbol. All existing code c. c copy code 1 # include <stdio. h> 2 3 _ attribute _ (weak) int I = 1; 4 5 int main (int argc, char ** argv) 6 {7 printf ("I = % d \ n", I); 8 return 0; 9} the output of the copied code result I is not 2, not 1. So is that true for functions? Instead of looking at the function, you should first look at the strong and weak references that are further introduced by the strong and weak symbols. The overview of strong and weak references in the book is that if a strong reference is not defined, the link will certainly report an error, and if it is weak reference, no error will be reported. The default value of the linker is 0 (this is a good understanding of the function, that is, the entry address represented by the function symbol is 0. You must pay attention to the variable. Since it is a reference, it is the address, so the address of the variable is 0 like that of the function, rather than the value of the variable is 0 ). Is there any clear concept for strong/weak references? What is reference? What is the relationship between references and symbols? Here I will talk about my understanding (please correct me). The function name and variable name specified in the definition and description are the corresponding symbols, when calling a function or using a variable elsewhere in the Code, the description of the letter and the variable name are considered as references. In this way, symbols and references are actually something at the code level, it's just different from the environment. Strong symbols correspond to strong references, and weak symbols correspond to weak references. The above strong and weak references show that when a function is a weak reference, no matter whether the function is defined or not, no error will be reported during the link, in addition, we can determine whether to execute the function based on whether the function name is 0. In this way, libraries that contain these functions can be combined with our reference in the form of modules and plug-ins for ease of use and uninstallation, since strong symbols can overwrite weak symbols, strong and weak symbols, and strong and weak references, we can define a function to overwrite the functions in the library. First, determine whether to execute the function based on the conditions: code d. c 1 # include <stdio. h> 2 3 void func () 4 {5 printf ("func () #1 \ n"); 6} code e. c copy code 1 # include <stdio. h> 2 3 _ attribute _ (weak) void func (); 4 5 int main (int argc, char ** argv) 6 {7 if (func) 8 func (); 9 return 0; 10} copy the code to compile d. c, cc-c d. c Output d. o; compile e. c and link d. o, cc d. o e. c-o e outputs the executable file e and runs the function func normally. Compile e. c but do not link d. o. At this time, no error is reported, but func will not execute, because if (func) is false because it is not defined. Look at function coverage again: code f. c 1 # include <stdio. h> 2 3 _ attribute _ (weak) void func () 4 {5 printf ("func () #1 \ n"); 6} Code g. c copy code 1 # include <stdio. h> 2 3 void func () 4 {5 printf ("func () #2 \ n"); 6} 7 8 int main (int argc, char ** argv) 9 {10 func (); 11 return 0; 12} 13 ~ Copy the code compilation link and output the structure "func () #2 ". The above shows that the function and the variable are consistent. In fact, the corresponding variable can also be used before judgment as if using the function, but not to judge the value of the variable but the address of the variable, for example, code v1.c int I = 2; Code v2.c copy code 1 # include <stdio. h> 2 3 _ attribute _ (weak) extern int I; 4 5 int main (int argc, char ** argv) 6 {7 if (& I) 8 printf ("I = % d \ n", I); 9 return 0; 10} 11 ~ When the code is compiled and linked to v1, 2 is output; if the code is compiled but not linked to v1, no output is generated. In this case, we need to distinguish between definitions and declarations. __attribute _ (weak) int I defines variables and converts them to weak symbols. In this way, I allocates space, the _ attribute _ (weak) extern int I converts the originally defined variable I from a strong symbol to a weak symbol, resulting in weak reference instead of a strong reference when I is used. However, although the variable can do this, it is not as meaningful as the function. The above strong and weak references still use the _ attribute _ (weak) provided by GCC, and the book also mentions _ attribute _ (weakref )), the latter seems to better reflect the keyword "Reference. The reason why I use the former to introduce strong and weak references is that I understand the relationship between strong and weak symbols and strong references. For how to use _ attribute _ (weakref), here is a method (both of which have different usage methods ). Code. c 1 # include <stdio. h> 2 3 void bar () 4 {5 printf ("foo () \ n"); 6} code B. c copy code 1 # include <stdio. h> 2 3 static void foo () _ attribute _ (weakref ("bar"); 4 5 int main (int argc, char ** argv) 6 {7 if (foo) 8 foo (); 9 10 return 0; 11} copy the code and pay attention to the static modifier of function foo. if not, an error is returned, in this way, the function foo can only be used in this file.