MISRA C++ Declarations & Definitions
About 1622 wordsAbout 5 min
2026-03-25
Overview
Chapters 3, 7, and 8 of MISRA C++:2008 govern how identifiers, types, objects, and pointers are declared and defined. Correct declarations are foundational to safe, portable C++ — many vulnerabilities and undefined behaviours originate from incorrect or ambiguous declarations.
The One Definition Rule (ODR)
Rule 3-1-1 — Headers Usable in Multiple TUs (Required)
It shall be possible to include any header file in multiple translation units without violating the One Definition Rule.
This means headers must:
- Use include guards or
#pragma once - Not contain definitions of non-inline, non-template functions
- Not contain definitions of non-const, non-constexpr objects with external linkage
// header.h — NON-COMPLIANT: function definition without inline
// If included in two .cpp files, the linker sees two definitions of foo()
int32_t foo(void) { // Non-compliant — ODR violation
return 42;
}
// header.h — COMPLIANT
inline int32_t foo(void) { // Compliant — inline allows multiple definitions
return 42;
}Rule 3-2-2 — One Definition Rule Shall Not Be Violated (Required)
Every entity (class, function, variable with external linkage) shall have exactly one definition across the entire program.
// file_a.cpp
int32_t g_counter = 0; // Definition — OK in one TU
// file_b.cpp
int32_t g_counter = 0; // Non-compliant — second definition, ODR violation
// CORRECT: declare in header, define in exactly one .cpp
// header.h:
extern int32_t g_counter; // Declaration only
// file_a.cpp:
int32_t g_counter = 0; // One definition — CompliantRule 3-3-1 — External Linkage Declarations in Headers (Required)
Objects or functions with external linkage shall be declared in a header file.
// NON-COMPLIANT: extern declaration buried in a .cpp file
// file_b.cpp:
extern int32_t g_value; // Non-compliant — should be in a header
// COMPLIANT:
// shared.h:
extern int32_t g_value; // Compliant — reachable from all TUs
// shared.cpp:
int32_t g_value = 0; // DefinitionConst-Correctness
Rule 7-1-1 — Non-Modified Objects Shall Be const (Required)
A variable which is not modified shall be const-qualified.
// NON-COMPLIANT
void display(uint32_t len, int32_t* data) { // data never modified inside
for (uint32_t i = 0U; i < len; ++i) {
print(data[i]); // only reads data
}
}
// COMPLIANT
void display(uint32_t len, const int32_t* data) { // const correct
for (uint32_t i = 0U; i < len; ++i) {
print(data[i]);
}
}Rule 7-1-2 — Pointer/Reference Parameters as const (Required)
A pointer or reference parameter in a function shall be declared as pointer to const or reference to const if the corresponding object is not modified.
// NON-COMPLIANT: buffer is read-only but not declared const
bool validate_frame(uint8_t* buffer, uint32_t length) {
for (uint32_t i = 0U; i < length; ++i) {
if (buffer[i] == 0U) { return false; }
}
return true;
}
// COMPLIANT
bool validate_frame(const uint8_t* buffer, uint32_t length) {
for (uint32_t i = 0U; i < length; ++i) {
if (buffer[i] == 0U) { return false; }
}
return true;
}Type Definitions and Aliases
Rule 3-9-2 — Use Sized Integer Types (Advisory)
typedef names that indicate size and signedness should be used in place of the basic numerical types.
// NON-COMPLIANT (advisory): basic types whose size is platform-dependent
int counter; // int size varies: 16-bit, 32-bit, 64-bit
long value; // long size varies: 32-bit on MSVC, 64-bit on Linux 64-bit
// COMPLIANT: fixed-size integer types from <cstdint>
int32_t counter;
int64_t value;
uint8_t byte_data;
uint16_t word_data;
uint32_t dword_data;Rule 2-10-3 — Unique typedef Names (Required)
A typedef name shall be a unique identifier (not used for any other purpose in the program).
// NON-COMPLIANT: typedef name reused as variable name
typedef uint32_t MyType;
void func(void) {
uint8_t MyType = 5U; // Non-compliant — reuses typedef name
}
// COMPLIANT
typedef uint32_t MyType;
void func(void) {
uint8_t my_var = 5U; // Compliant — distinct name
}Object Declarations
Rule 8-0-1 — One Object Per Declaration (Required)
Multiple declarators shall not be used in the same declaration.
// NON-COMPLIANT: multiple declarators
int32_t a, b, c; // Non-compliant
int32_t *p1, p2; // Non-compliant and dangerous: p2 is int32_t, not int32_t*
// COMPLIANT: one object per declaration
int32_t a;
int32_t b;
int32_t c;
int32_t* p1;
int32_t* p2;Rule 3-4-1 — Minimise Scope of Variables (Required)
An identifier declared to be an object or type shall be defined in a block that minimises its visibility.
// NON-COMPLIANT: variable declared at wider scope than needed
int32_t result; // declared here but only used inside the loop
for (uint32_t i = 0U; i < 10U; ++i) {
result = compute(i); // Non-compliant — result should be inside loop
store(result);
}
// COMPLIANT: narrowest possible scope
for (uint32_t i = 0U; i < 10U; ++i) {
int32_t result = compute(i); // Compliant — declared where first used
store(result);
}Pointer Declarations
Rule 8-3-1 — & and * Bind to Type (Required)
Parameters in a function declaration that are arrays shall be declared as pointers.
Rule 8-5-2 — Braces Required for Multi-Dimensional Arrays (Required)
Braces shall be used to indicate and match the structure in non-zero initialisation of arrays and structures.
// NON-COMPLIANT: no braces for inner arrays
int32_t arr[2][3] = { 0, 1, 2, 3, 4, 5 }; // Non-compliant
// COMPLIANT: nested braces match structure
int32_t arr[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; // CompliantPointer Arithmetic and Pointer Safety
Rule 5-0-15 — Array Types in Subscript Expressions (Required)
Array indexing shall be the only form of pointer arithmetic.
// NON-COMPLIANT: raw pointer arithmetic
uint8_t buffer[64];
uint8_t* p = buffer;
uint8_t val = *(p + 5); // Non-compliant — pointer arithmetic
// COMPLIANT: array subscript
uint8_t val = buffer[5]; // CompliantRule 5-0-16 — No Pointer Subtraction on Different Arrays (Required)
Pointer arithmetic shall only be applied to pointers that address elements of the same array.
// NON-COMPLIANT: subtracting pointers into different arrays
uint8_t arr1[10];
uint8_t arr2[10];
ptrdiff_t diff = &arr2[0] - &arr1[0]; // Non-compliant — undefined behaviour
// COMPLIANT: only within the same array
ptrdiff_t diff = &arr1[5] - &arr1[0]; // Compliant — same arrayRule 5-0-17 — No Pointer Comparison Across Arrays (Required)
The relationship operators (<, <=, >, >=) shall not be applied to pointer types except where they point into the same array.
Rule 8-4-1 — Function Parameter Types Shall Be Declared (Required)
Functions shall not be declared using the ellipsis notation (variadic ...).
// NON-COMPLIANT: variadic function
void log_message(const char* fmt, ...); // Non-compliant
// COMPLIANT: explicitly typed parameters
void log_message(uint8_t level, const char* message, uint32_t code);
// Or use variadic templates (MISRA C++:2023 allows with restrictions)
template<typename... Args>
void log_safe(Args&&... args);Function Declarations
Rule 8-4-2 — Identifiers Used in Declarations Shall Be Identical (Required)
The identifiers used in the declaration and definition of a function shall be identical.
// NON-COMPLIANT: parameter names differ between declaration and definition
// header.h:
void configure_device(uint32_t speed, uint8_t mode);
// source.cpp:
void configure_device(uint32_t s, uint8_t m) { // Non-compliant — different names
...
}
// COMPLIANT:
void configure_device(uint32_t speed, uint8_t mode) { // Names match
...
}Rule 8-4-4 — Function Identifiers in Expressions (Required)
A function identifier shall either be used to call the function or it shall be preceded by &.
// NON-COMPLIANT: function name used without call or address-of
typedef void (*FuncPtr)(void);
FuncPtr p = some_function; // Non-compliant — should use &some_function
// COMPLIANT
FuncPtr p = &some_function; // Compliant — explicit &Static Storage Duration
Rule 3-3-2 — Static Re-Declarations (Required)
If a function has internal linkage, all re-declarations shall include the static storage class specifier.
// NON-COMPLIANT: first declaration has static, re-declaration does not
static void helper(void); // First declaration — internal linkage
void helper(void) { // Non-compliant — missing static
...
}
// COMPLIANT
static void helper(void);
static void helper(void) { // Compliant — both have static
...
}Bit Fields
Rule 9-6-1 — Bit Fields Shall Be Declared as Integral Types (Required)
Bit fields shall be of integral type, and shall be either unsigned int or signed int (or a typedef of those).
// NON-COMPLIANT
struct Flags {
bool active : 1; // Non-compliant — bool bit field
float value : 4; // Non-compliant — float bit field (impossible practically)
uint8_t code : 3; // Non-compliant — uint8_t not guaranteed for bit fields
};
// COMPLIANT
struct Flags {
uint32_t active : 1; // Compliant — unsigned int
uint32_t code : 3; // Compliant — unsigned int
uint32_t mode : 4; // Compliant — unsigned int
};Rule 9-6-2 — Named Bit Fields Shall Be Either Signed or Unsigned Int (Required)
Named bit fields of type int shall be prohibited because signedness of plain int is implementation-defined.
// NON-COMPLIANT
struct Control {
int flag : 1; // Non-compliant — signedness of int:1 is impl-defined
};
// COMPLIANT
struct Control {
uint32_t flag : 1; // Compliant — explicitly unsigned
int32_t sign : 4; // Compliant — explicitly signed
};Summary: Key Declaration & Definition Rules
| Rule | Level | Rule Summary |
|---|---|---|
| 3-1-1 | Required | Headers usable in multiple TUs without ODR violation |
| 3-2-2 | Required | Don't violate ODR |
| 3-3-1 | Required | External linkage declarations in header files |
| 3-4-1 | Required | Declare variables in the narrowest possible scope |
| 3-9-2 | Advisory | Use sized integer typedefs |
| 7-1-1 | Required | Unmodified objects shall be const |
| 7-1-2 | Required | Unmodified pointer/reference params shall be const |
| 8-0-1 | Required | One declarator per declaration |
| 8-4-1 | Required | No variadic functions (...) |
| 8-4-2 | Required | Declaration and definition identifiers must match |
| 8-4-4 | Required | Function identifiers: call or use & |
| 9-6-1 | Required | Bit fields must be integral (unsigned/signed int) |
| 9-6-2 | Required | No plain int bit fields — specify signedness |