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.