How does a link work when there are two .c files with global variables of the same character, but with different types?

WITH

Let's say I have the following C-modules:

MODULE 1

#include <stdio.h> int x; int main(){ foo(); printf("%i\n",x); return 0; } 

MODULE 2

 double x; void foo(){ x = 3.14; } 

My question is: what does the linker do in this case? In the tutorial I'm reading, he says that the compiler selects only one of two weak global variables for the linker symbol table. Which of these two is chosen? Or are both selected? If so, why? Thanks.

+6
source share
2 answers

C says this behavior is undefined.

(C99, 6.9p5) "If an identifier declared with an external link is used in the expression (except as part of the operand of the sizeof operator, the result of which is an integer constant), somewhere in the entire program there must be exactly one external definition for the identifier, in otherwise there should be no more than one "

Being undefined behavior means that the linker can interrupt the binding process in the presence of multiple definitions of external objects.

Linkers are now good (or evil, you can choose) and usually have default extensions to handle multiple definitions of external objects and in some cases don't crash.

If you use gcc and ld from binutils, you will get an error if your two objects are explicitly initialized. For example, you have int x = 0; in the first translation unit and double x = 0.0; .

Otherwise, if one of the external objects is not explicitly initialized (the situation in your example), gcc will seamlessly combine the two objects into one symbol. You can still ask the linker to report a warning by passing it the --warn-common option.

For example, when linking modules:

gcc -Wl,--warn-common module1.o module2.o

To interrupt the binding process, you can ask the linker to treat all warnings as errors using the --fatal-warnings ( -Wl,--fatal-warnings,--warn-common ) option.

Another way for the bind process to be aborted is to use the -fno-common option of the compiler, as explained by @teppic in his answer. -fno-common prevents external objects from receiving a common character type when compiling. If you do this both for the module and then for the link, you will also get a linker error of several definitions.

gcc -Wall -fno-common -c module1.c module2.c

gcc module1.o module2.o

+5
source

If the implementation supports several external definitions, you will get one object that is effectively passed to each type in each module, as in some implicit combined variable. The amount of memory for the larger type will be allocated, and both will behave as external declarations.

If you are compiling using clang or gcc, use the -fno-common option to cause an error for this.

Here is a section from the gcc manual:

  In C code, controls the placement of uninitialized global variables. Unix C compilers have traditionally permitted multiple definitions of such variables in different compilation units by placing the variables in a common block. This is the behavior specified by -fcommon, and is the default for GCC on most targets. On the other hand, this behavior is not required by ISO C, and on some targets may carry a speed or code size penalty on variable references. The -fno-common option specifies that the compiler should place uninitialized global variables in the data section of the object file, rather than generating them as common blocks. This has the effect that if the same variable is declared (without "extern") in two different compilations, you will get a multiple- definition error when you link them. 

This setting effectively ensures strict ISO C compliance for multiple definitions.

This behavior is accepted for external variables of the same type. As stated in the GCC manual, most compilers support this, and (assuming the types are the same), the C99 standard defines its use as an extension.

+1
source

All Articles