9.10.27 weak
The weak
attribute causes the declaration to be emitted
as a weak symbol. A weak symbol may be superseded by a global definition. When
weak
is applied to a reference to an external symbol, the symbol is
not required for linking. For example:
extern int __attribute__((__weak__)) s;
int foo() {
if (&s) return s;
return 0; /* possibly some other value */
}
In the above program, if s
is not defined by some other
module, the program will still link but s
will not be given an address.
The conditional verifies that s
has been defined (and returns its value
if it has). Otherwise ‘0’
is returned. There are many uses for this
feature, mostly to provide generic code that can link with an optional library.
The weak
attribute may be applied to functions as well
as variables:
extern int __attribute__((__weak__)) compress_data(void *buf);
int process(void *buf) {
if (compress_data) {
if (compress_data(buf) == -1) /* error */
}
/* process buf */
}
In the above code, the function compress_data
will be
used only if it is linked in from some other module. Deciding whether or not to use the
feature becomes a link-time decision, not a compile time decision.
The affect of the weak
attribute on a definition is
more complicated and requires multiple files to describe:
/* weak1.c */
int __attribute__((__weak__)) i;
void foo() {
i = 1;
}
/* weak2.c */
int i;
extern void foo(void);
void bar() {
i = 2;
}
main() {
foo();
bar();
}
Here the definition in weak2.c
of i
causes the symbol to become a strong definition. No link error is emitted and both
i
’s refer to the same storage location. Storage is allocated for
weak1.c
’s version of i
, but this space is not
accessible.
There is no check to ensure that both versions of i
have the same type; changing i
in weak2.c
to be of
type float
will still allow a link, but the behavior of function
foo
will be unexpected. foo
will write a value
into the least significant portion of our 32-bit float value. Conversely, changing the
type of the weak definition of i
in weak1.c
to type
float
may cause disastrous results. We will be writing a 32-bit
floating point value into a 16-bit integer allocation, overwriting any variable stored
immediately after our i
.
In the cases where only weak
definitions exist, the
linker will choose the storage of the first such definition. The remaining definitions
become inaccessible.
The behavior is identical, regardless of the type of the symbol; functions and variables behave in the same manner.