Weak Symbols vs Strong Symbols : When working with C programming, especially in embedded systems or system-level development, you will often encounter the concepts of weak symbols and strong symbols. These terms come into play during the linking stage of compilation. Understanding them is crucial for writing flexible, modular, and maintainable code.
In this article, we’ll explore the difference between weak symbols and strong symbols in C, how they work, and where they are used.
What is a Weak symbol and Strong Symbols in C ?
In C programming, symbols represent functions or variables that the linker resolves during compilation. Strong symbols are the default definitions of global variables or functions, and only one strong symbol with the same name can exist across a program. If multiple strong symbols are present, the linker throws a multiple-definition error.
On the other hand, weak symbols are declared using the __attribute__((weak))
attribute. They act as fallback definitions, meaning if a strong symbol with the same name is available, it overrides the weak symbol. If no strong definition exists, the weak symbol is used.
This mechanism is particularly useful in embedded systems, libraries, and modular applications, where weak symbols provide default implementations (such as interrupt handlers or library functions) that can be optionally overridden by the developer.
Key difference:
- Strong symbols = Default and unique definitions.
- Weak symbols = Flexible fallback definitions, overridden by strong symbols if available.
What are Symbols in C?
In simple terms, a symbol is the name that represents a function or variable in your program. For example:
int myVar = 10; // 'myVar' is a symbol
void myFunction() {} // 'myFunction' is a symbol
When you compile your code, the compiler generates object files with these symbols. The linker then resolves them to produce the final executable.
Strong symbols in C
A strong symbol is the default type of symbol generated by the compiler when you define a global variable or function.
👉 Characteristics of strong symbols:
- Created when you define a function or variable without the
weak
attribute. - Only one definition of a strong symbol can exist across the program.
- If two strong symbols with the same name are defined in different files, the linker will throw an error (multiple definition error).
Example of Strong Symbol
int data = 100; // Strong symbol by default
void printData() {
printf("%d\n", data);
}
Here, data
and printData
are strong symbols.
Weak Symbols in C
A weak symbol is a symbol that tells the linker:
“Use this symbol if no strong definition is found, otherwise ignore me.”
👉 Characteristics of weak symbols:
- Declared using the
__attribute__((weak))
keyword. - Can be overridden by a strong symbol with the same name.
- If no strong symbol is provided, the weak symbol is used as a fallback.
Example of Weak Symbol
__attribute__((weak)) void myFunction() {
printf("Default weak function\n");
}
If another file defines a strong version of myFunction
, the weak version will be ignored by the linker.
Weak vs Strong Symbols in C
Feature | Strong Symbol | Weak Symbol |
---|---|---|
Default behavior | Yes | No (explicitly defined) |
Multiple definitions | Not allowed (linker error) | Allowed, but overridden by strong |
Use case | Normal variables/functions | Fallbacks, optional overrides |
Example use | int var = 10; | __attribute__((weak)) void func() |
Why Use Weak Symbols?
Weak symbols are very useful in system programming and embedded systems:
- Fallback Implementation
- Provide a default implementation of a function.
- Example: weak logging functions can be overridden by user-defined strong ones.
- Flexibility in Libraries
- Library authors often define weak symbols so developers can override them with custom implementations.
- Bootloaders & Firmware
- In embedded systems, weak symbols are used for interrupt handlers or startup code, which can later be overridden by user-defined handlers.
Practical Example – Weak vs Strong
// weak_function.c
#include <stdio.h>
__attribute__((weak)) void hello() {
printf("Hello from weak function!\n");
}
// strong_function.c
#include <stdio.h>
void hello() {
printf("Hello from strong function!\n");
}
// main.c
int main() {
hello();
return 0;
}
👉 If you compile all three files together:
- Output will be: “Hello from strong function!”
- The weak symbol is ignored because a strong definition exists.
👉 If you compile without strong_function.c
:
- Output will be: “Hello from weak function!”
This demonstrates the priority of strong symbols over weak symbols.
Weak Symbols vs Strong Symbols
In C programming, symbols are names that represent functions or variables during the compilation and linking stages. The linker decides how these symbols are resolved. Based on their definition, they can be classified as strong symbols or weak symbols.
Strong Symbols in C
- Definition: Default symbols created when you define a global variable or function normally.
- Characteristics:
- Only one strong symbol with the same name can exist.
- If multiple strong symbols are defined → linker error.
- Used for actual, unique implementations.
- Example:
int count = 0; // Strong symbol void myFunction() { } // Strong symbol
Weak Symbols in C
- Definition: Symbols explicitly marked as weak using
__attribute__((weak))
. - Characteristics:
- Can be overridden by a strong symbol with the same name.
- If no strong symbol exists, the weak symbol is used.
- Provide default/fallback implementations.
- Example:
__attribute__((weak)) void handler() { printf("Default weak handler\n"); }
Key Differences Between Weak and Strong Symbols
Aspect | Strong Symbol | Weak Symbol |
---|---|---|
Definition | Default function/variable definition | Defined using __attribute__((weak)) |
Multiplicity | Only one allowed | Multiple allowed (overridden if strong exists) |
Priority | Always preferred by linker | Used only if strong symbol not found |
Error Handling | Multiple definitions → Linker error | No error, just overridden |
Use Case | Unique implementation of code | Fallbacks, library defaults, embedded handlers |
Example Demonstrating Weak vs Strong
// weak.c
#include <stdio.h>
__attribute__((weak)) void hello() {
printf("Hello from weak function\n");
}
// strong.c
#include <stdio.h>
void hello() {
printf("Hello from strong function\n");
}
// main.c
int main() {
hello();
return 0;
}
👉 If all files are compiled → “Hello from strong function”
👉 If strong.c
is not compiled → “Hello from weak function
Advantages of Weak and Strong Symbols
Advantages of Strong Symbols
- Ensure uniqueness of functions and variables across the program.
- Prevent accidental multiple definitions through linker checks.
- Provide clear ownership of implementation (no ambiguity).
Advantages of Weak Symbols
- Allow default implementations that can be overridden.
- Useful for library development – provides flexibility to end-users.
- Helpful in embedded systems for fallback code like interrupt handlers.
- Enable code modularity and easy customization without changing base code.
Disadvantages of Weak and Strong Symbols
Disadvantages of Strong Symbols
- Multiple definitions lead to linker errors.
- Not flexible – you cannot provide optional overrides.
Disadvantages of Weak Symbols
- Can cause unintended overrides if strong symbols are accidentally defined.
- Harder to debug, since weak definitions may silently get replaced.
- May lead to inconsistent behavior if not properly documented.
Real-Time Applications of Weak and Strong Symbols
- Embedded Systems (Microcontrollers & Firmware)
- Startup code often defines weak interrupt handlers.
- Developers can override them with strong custom handlers.
- Operating Systems and Libraries
- System libraries provide weak functions as placeholders, allowing developers to replace them with optimized implementations.
- Bootloaders
- Weak symbols act as default functions for initialization routines, overridden later by board-specific implementations.
- Driver Development
- Hardware drivers may use weak functions to allow custom extensions without modifying the core code.
- Logging and Debugging Systems
- A weak logging function may be defined in a library, which can be overridden by a strong symbol to implement device-specific logging.
Key Takeaways of weak and strong symbols in C
- Strong symbols are the default; they must be unique across your program.
- Weak symbols act as placeholders or fallback implementations.
- If both exist, the strong symbol overrides the weak symbol.
- Useful in embedded systems, libraries, and modular applications where flexibility and default behavior are important.
FAQ of Weak and Strong symbols in C
1.What is a weak symbol in C programming?
Ans: A weak symbol in C is a function or variable marked with __attribute__((weak))
. It provides a default implementation that can be overridden by a strong symbol if available.
2.What is a strong symbol in C programming?
Ans: A strong symbol is the default definition of a global function or variable in C. Only one strong symbol with the same name can exist; otherwise, the linker reports a multiple-definition error.
3.How does the linker resolve weak and strong symbols in C?
Ans: The linker always gives priority to strong symbols. If both weak and strong symbols of the same name exist, the strong one overrides the weak one. If no strong symbol is found, the weak symbol is used.
4.Why are weak symbols used in embedded systems?
Ans: Weak symbols are widely used in embedded systems to provide default implementations of functions, such as interrupt handlers or startup code, which can later be overridden with strong custom implementations.
5.Weak vs strong symbols in embedded C examples
Ans: For example, in an embedded project, a library might provide a weak function for logging, while the developer can define a strong logging function to customize it. If the strong symbol is defined, it overrides the weak one.
6.Advantages and disadvantages of weak symbols in C
Ans:
Advantages: Provide fallback functions, flexibility in libraries, easy overrides, useful in firmware and drivers.
Disadvantages: Can be accidentally overridden, harder to debug, and may cause inconsistent behavior if not documented.
7.Real-time applications of weak symbols in embedded systems
Ans:
a) Interrupt handlers in microcontrollers
b) Default startup code in bootloaders
c) System libraries providing optional implementations
d) Logging/debugging placeholders overridden by user code
8.How to override weak functions in C
Ans: To override a weak function, simply define a strong function with the same name in your program. The linker will ignore the weak definition and use the strong one.
9.Weak attribute in GCC explained
Ans: In GCC, the __attribute__((weak))
keyword is used to declare a symbol as weak. This tells the linker to treat it as a fallback definition, which can be replaced if a strong definition exists.
1.What is a weak symbol in C?
A weak symbol in C is a function or variable marked with __attribute__((weak))
. It can be overridden by a strong definition if available.
2.What is a strong symbol in C?
A strong symbol is the default type of global function or variable in C. Only one strong symbol of the same name can exist; otherwise, the linker throws a multiple definition error.
3.What happens if both weak and strong symbols exist in C?
The strong symbol takes precedence, and the weak symbol is ignored by the linker.
4.Why are weak symbols used in embedded systems?
Weak symbols allow developers to provide default implementations (e.g., interrupt handlers) which can later be overridden by user-defined strong implementations.
5.Can two strong symbols exist with the same name?
No, multiple strong symbols with the same name cause a linker error.
You can also Visit other tutorials of Embedded Prep
- Multithreading in C++
- Multithreading Interview Questions
- Multithreading in Operating System
- Multithreading in Java
- POSIX Threads pthread Beginner’s Guide in C/C++
- Speed Up Code using Multithreading
- Limitations of Multithreading
- Common Issues in Multithreading
- Multithreading Program with One Thread for Addition and One for Multiplication
- Advantage of Multithreading
- Disadvantages of Multithreading
- Applications of Multithreading: How Multithreading Makes Modern Software Faster and Smarter”
- Master CAN Bus Interview Questions 2025
- What Does CAN Stand For in CAN Bus?
- CAN Bus Message Filtering Explained
- CAN Bus Communication Between Nodes With Different Bit Rates
- How Does CAN Bus Handle Message Collisions
- Message Priority Using Identifiers in CAN Protocol

Mr. Raj Kumar is a highly experienced Technical Content Engineer with 7 years of dedicated expertise in the intricate field of embedded systems. At Embedded Prep, Raj is at the forefront of creating and curating high-quality technical content designed to educate and empower aspiring and seasoned professionals in the embedded domain.
Throughout his career, Raj has honed a unique skill set that bridges the gap between deep technical understanding and effective communication. His work encompasses a wide range of educational materials, including in-depth tutorials, practical guides, course modules, and insightful articles focused on embedded hardware and software solutions. He possesses a strong grasp of embedded architectures, microcontrollers, real-time operating systems (RTOS), firmware development, and various communication protocols relevant to the embedded industry.
Raj is adept at collaborating closely with subject matter experts, engineers, and instructional designers to ensure the accuracy, completeness, and pedagogical effectiveness of the content. His meticulous attention to detail and commitment to clarity are instrumental in transforming complex embedded concepts into easily digestible and engaging learning experiences. At Embedded Prep, he plays a crucial role in building a robust knowledge base that helps learners master the complexities of embedded technologies.
Leave a Reply