top of page

Data Type Qualifiers + Storage Class Interactions

  • Writer: Ashok Kumar Kumawat
    Ashok Kumar Kumawat
  • Feb 8
  • 2 min read

Perfect, let’s extend our revision into Data Type Qualifiers + Storage Class Interactions. This is where embedded C really differs from desktop C, because qualifiers directly affect how the compiler generates code for hardware registers, ISRs, and memory-constrained systems.

1. Concept Overview

  • Data type qualifiers: const, volatile, signed, unsigned, restrict (rare in embedded).

  • Storage classes: static, extern, register, auto (default).

  • Together, they define scope, lifetime, mutability, and optimization behavior of variables.

2. Embedded Industry Usage

  • volatile static: Flags updated in ISRs but persistent across function calls.

  • const extern: Read-only configuration data shared across modules.

  • volatile extern: Hardware registers declared in a header, accessed across multiple source files.

  • const static: Lookup tables stored in Flash, local to a file.

  • register: Rarely used in modern compilers; optimization is usually automatic.

3. Practical Examples

Example 1: volatile static ISR flag

#include <stdint.h>

static volatile uint8_t adc_ready = 0;

void ADC_ISR(void) {
    adc_ready = 1;  // ISR sets flag
}

void main(void) {
    while (!adc_ready) {
        // Wait until ADC ISR sets flag
    }
}
  • Combines persistence (static) with no optimization (volatile).

Example 2: consT extern configuration

// config.h
extern const uint16_t baud_rate;

// config.c
const uint16_t baud_rate = 9600;
  • Shared constant across modules, stored in Flash.

Example 3: volatile extern hardware register

// device.h
extern volatile uint8_t* const UART_DR;

// device.c
volatile uint8_t* const UART_DR = (uint8_t*)0x4000C000;

void send_byte(uint8_t data) {
    *UART_DR = data;  // Write to hardware register
}

4. Best Practices

  • Always combine volatile with hardware registers or ISR-shared variables.

  • Use const for calibration tables, configuration constants → saves RAM.

  • Explicitly declare extern for cross-file variables to avoid multiple definitions.

  • Avoid register keyword; modern compilers optimize better.

  • MISRA-C: Always initialize static variables; avoid hidden dependencies with extern.

5. When to Use

  • volatile static: ISR flags, persistent hardware state.

  • const extern: Shared configuration constants across modules.

  • volatile extern: Hardware registers accessed globally.

  • const static: Lookup tables, ROM-stored data local to a file.

  • register: Only in legacy code; compilers usually ignore it.

6. Memory & Performance Considerations

  • static: Allocated in global/static memory → persists for program lifetime.

  • extern: No memory allocated; just a reference.

  • volatile: Prevents compiler optimizations → may increase code size and execution time, but ensures correctness.

  • const: Stored in Flash/ROM → saves RAM.

  • register: Suggests CPU register allocation, but compilers usually decide automatically.

Recent Posts

See All
Q&A: C Code

Q1: How do you find the size of an array in C? Q2: What is an array of pointers in C, and why is it useful? Q3: How can function pointers be used to trigger callbacks in C? Q4: How can we determine th

 
 
 
Bubble Sort Concept

Bubble Sort repeatedly compares adjacent elements and swaps them if they are in the wrong order. After each pass, the largest element "bubbles up" to its correct position at the end. C Code Example #i

 
 
 
Storage Classes in Embedded C

Excellent, let’s now systematically cover Storage Classes in Embedded C with the structured breakdown you asked for. 1. Concept Overview Storage classes define scope, lifetime, and visibility of varia

 
 
 

Comments


© 2035 by Robert Caro. Powered and secured by Wix

bottom of page