Weak Symbols vs Strong Symbols in C

Table of Contents

  1. Introduction
  2. Strong Symbols
  3. Weak Symbols
  4. Benefit of Weak Symbols
  5. Combining the Weak and Strong Symbols
  6. Conclusion

1. Introduction:

In the world of C programming, symbols play a vital role in connecting different parts of a program during the linking process. Two types of symbols, namely weak and strong symbols, influence the linking behavior, providing developers with flexibility and control over symbol resolution. This article explores the concepts of weak and strong symbols, their characteristics, and how they impact the linking process in C.

2. Strong Symbols:

A strong symbol, also known as a strong definition, is a symbol that represents a well-defined entity such as a variable or a function with a unique memory location. When the linker encounters multiple strong definitions of the same symbol in different translation units, it raises an error, as it cannot resolve the ambiguity.

Example of a Strong Symbol:

//Strong Symbol

int strong_variable = 14;


If another source file attempts to define strong_variable again, the linker would flag an error due to the conflicting strong definitions.

3. Weak Symbols:

A weak symbol, on the other hand, allows for multiple definitions of the same symbol without causing linker errors. The compiler and linker treat weak symbols differently, providing a way to have default or fallback definitions that can be overridden by stronger definitions.

Example of a Weak Symbol:

// weak_symbol

int weak_variable __attribute__((weak)) = 10;


In this example, weak_variable is marked as weak using the __attribute__((weak)) attribute. If another source file provides a strong definition of weak_variable, the strong definition takes precedence during the linking process.

4. Benefits of Weak Symbols:

Default Implementations: Weak symbols enable the definition of default implementations that can be overridden if necessary.
Plug-in Architectures: Weak symbols are useful in plug-in architectures where modules may or may not provide specific functionalities. A weak symbol can act as a default implementation that is only used if the module doesn't provide its own.

5. Combining Weak and Strong Symbols:

Developers can leverage both weak and strong symbols to create flexible and extensible code. For instance, a library may expose weak symbols as hooks for users to override, while providing strong symbols as essential components.

    Example:

     source_file.c

//strong declarable that will be overriding the weak_variable definition
int weak_variable = 10;

main.c

#include 
int weak_variable __attribute__((weak)) = 100;

int main()
{
    printf("%d", weak_variable );
    return 0;
}

Output is = 10
In this example, there are two source files 1) main.c 2) source_file.c. main.c has the weak symbol that is weak_variable it has the default value 100 and in the second source file source_file.c has the strong symbol defination of the weak_variable with value 5. When both files are compiled together then the final weak_vairable value outcomes 5.

6. Conclusion:

Understanding the distinctions between weak and strong symbols in C is crucial for designing modular, extensible, and maintainable code. Strong symbols represent definitions with a strict binding during linking, causing conflicts if defined more than once. Weak symbols, however, have a more flexible binding, allowing multiple definitions without linker errors, with a default chosen during linking. Strong symbols represent definitive entities, while weak symbols provide a flexible mechanism for customization and extension. By strategically using weak and strong symbols, developers can strike a balance between enforcing essential components and allowing for optional or replaceable parts in their software projects.