Fundamentals 19 min read

Master C Preprocessor Tricks, Static/Const/Volatile Keywords, and Common Embedded Pitfalls

This article walks through essential C concepts for embedded development, including macro definitions for constants and MIN, the use of #error, infinite loops, variable declaration patterns, the roles of static, const, and volatile, bit‑mask operations, absolute address access, ISR constraints, unsigned‑int quirks, safe typedef usage, and tricky expressions like a+++b.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Master C Preprocessor Tricks, Static/Const/Volatile Keywords, and Common Embedded Pitfalls

1. Defining Constants with Macros

Use #define SEC_YEAR (365*24*60*60)UL to define the number of seconds in a year. The UL suffix forces the constant to be an unsigned long, preventing overflow on 16‑bit targets. The macro demonstrates basic #define syntax, constant‑expression evaluation by the preprocessor, and the importance of parentheses.

2. Safe Minimum Macro

The naïve macro #define MIN(a,b) ((a)<=(b)?(a):(b)) suffers from multiple evaluation and type‑mismatch problems. Safer alternatives evaluate each argument exactly once and preserve type safety:

#define min_i(x,y)    ((x)<=(y)?(x):(y))
#define min_t(type,x,y) ({ type _x = (x); type _y = (y); _x < _y ? _x : _y; })
#define min(x,y) ({ const typeof(x) _x = (x); const typeof(y) _y = (y); (void)(&_x == &_y); _x < _y ? _x : _y; })

These macros use a temporary variable (or a GNU statement expression) so that side‑effects such as p++ are performed only once.

3. Compile‑Time Checks with #error

Embedding #error "XXX has been defined" inside an #ifdef / #else block forces a compilation failure when an unexpected macro is defined. This guarantees that the build environment matches the programmer’s assumptions.

4. Writing Infinite Loops in Embedded C

Three idiomatic ways to create a dead‑loop that never returns:

while(1) {}
for(;;) {}
loop: … goto loop;

5. Variable and Pointer Declarations

Common declaration patterns used in interview questions:

int a;                // integer
int *a;              // pointer to int
int **a;             // pointer to pointer to int
int a[10];           // array of 10 ints
int *a[10];          // array of 10 pointers to int
int (*a)[10];        // pointer to an array of 10 ints
int (*a)(int);       // pointer to a function taking int and returning int
int (*a[10])(int);   // array of 10 function pointers with the same signature

6. The static Keyword

Three distinct uses in C:

Static local variables retain their value between function calls.

Static global variables have internal linkage, making them invisible to other translation units.

Static functions are limited to the defining source file.

In C++ the keyword can also qualify class data members and member functions, providing shared storage and file‑level access.

7. The const Keyword

const

makes an object read‑only. It can qualify variables, function parameters, and return values, enabling:

Compile‑time type safety (preventing accidental modification).

Potential compiler optimisations because the value cannot change.

Self‑documenting code that expresses intent.

8. The volatile Keyword

volatile

tells the compiler that a variable may be changed by external factors (hardware, ISR, another thread). The optimizer must always reload the value from memory. Typical uses:

Memory‑mapped hardware registers.

Variables accessed from an interrupt service routine.

Shared variables in a multithreaded environment.

9. Bit‑Mask Operations

Define a mask and manipulate a static integer without affecting other bits:

#define BIT3 (0x1 << 3)
static int a;
void set_bit3(void) { a |= BIT3; }
void clear_bit3(void) { a &= ~BIT3; }

10. Accessing an Absolute Memory Address

Cast the address to a pointer and write the desired value. This is legal in a strictly conforming ANSI C compiler:

int *ptr = (int *)0x67A9;
*ptr = 0xAA66;

11. Pitfalls of Using __interrupt

Interrupt Service Routines (ISRs) must obey the following rules:

They must have a void return type (no return value).

They must not take parameters.

Avoid floating‑point operations and non‑reentrant library calls such as printf, because many embedded compilers do not provide a re‑entrant floating‑point context.

12. Unsigned‑Int Comparison Quirk

In the expression

unsigned int a = 6;
int b = -20;
(a + b > 6) ? puts("> 6") : puts("<= 6");

the signed operand b is converted to unsigned, yielding a large positive value. Consequently the condition is true and the program prints > 6.

13. Complement of Zero

For portable code, obtain a bitwise complement of zero with unsigned int compzero = ~0;. Hard‑coding 0xFFFF assumes a 16‑bit int and is not portable.

14. Behaviour of malloc(0)

Calling malloc(0) may return a non‑NULL pointer. The pointer can safely be passed to free. A typical test prints “Got a valid pointer”.

15. typedef vs Macro for Pointer Types

Using typedef struct s *tPS; is safer than #define dPS struct s *. The typedef binds the pointer to the type, preventing accidental variable definitions such as struct s *p1, p2; where p2 would be a plain struct, not a pointer.

16. The Curious Expression a+++b

The token sequence is parsed as a++ + b. After evaluation a becomes 6, b remains 7, and c receives 12.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

C programmingMacrosVolatile keywordstatic keywordConst keywordPointer types
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.