pw_preprocessor#
Helpful preprocessor macros
Stable C C++
The preprocessor module provides various helpful preprocessor macros.
Compatibility#
C and C++
Headers#
The preprocessor module provides several headers.
pw_preprocessor/apply.h#
Defines general macro to support macro expansion. Includes the following macro:
API Reference#
-
PW_APPLY(macro, separator, forwarded_arg, ...)#
Repeatedly applies the given macro for each argument provided. The given macro expands to accept an index value of the current argument, the forwarded argument provided, and the current argument. The forwarded argument is used in every macro call. The separator expands to accept the index argument as well as the forwarded argument. The last separator is omitted.
The example below shows how this macro expands, based on a pre-defined macro and separator. The statement
PW_APPLY(MACRO, SEP, ARG, a0, a1)
expands to:MACRO(0, ARG, a0) SEP(0, ARG) MACRO(1, ARG, a1)
pw_preprocessor/arguments.h#
Defines macros for handling variadic arguments to function-like macros. Macros include the following:
-
PW_DELEGATE_BY_ARG_COUNT(name, ...)#
Selects and invokes a macro based on the number of arguments provided. Expands to
<name><arg_count>(...)
. For example,PW_DELEGATE_BY_ARG_COUNT(foo_, 1, 2, 3)
expands tofoo_3(1, 2, 3)
.This example shows how
PW_DELEGATE_BY_ARG_COUNT
could be used to log a customized message based on the number of arguments provided.#define ARG_PRINT(...) PW_DELEGATE_BY_ARG_COUNT(_ARG_PRINT, __VA_ARGS__) #define _ARG_PRINT0(a) LOG_INFO("nothing!") #define _ARG_PRINT1(a) LOG_INFO("1 arg: %s", a) #define _ARG_PRINT2(a, b) LOG_INFO("2 args: %s, %s", a, b) #define _ARG_PRINT3(a, b, c) LOG_INFO("3 args: %s, %s, %s", a, b, c)
When used,
ARG_PRINT
expands to the_ARG_PRINT#
macro corresponding to the number of arguments.ARG_PRINT(); // Outputs: nothing! ARG_PRINT("a"); // Outputs: 1 arg: a ARG_PRINT("a", "b"); // Outputs: 2 args: a, b ARG_PRINT("a", "b", "c"); // Outputs: 3 args: a, b, c
-
PW_COMMA_ARGS(...)#
Expands to a comma followed by the arguments if any arguments are provided. Otherwise, expands to nothing. If the final argument is empty, it is omitted. This is useful when passing
__VA_ARGS__
to a variadic function or template parameter list, since it removes the extra comma when no arguments are provided.PW_COMMA_ARGS
must NOT be used when invoking a macro from another macro.For example.
PW_COMMA_ARGS(1, 2, 3)
, expands to, 1, 2, 3
, whilePW_COMMA_ARGS()
expands to nothing.PW_COMMA_ARGS(1, 2, )
expands to, 1, 2
.
pw_preprocessor/boolean.h#
Defines macros for boolean logic on literal 1s and 0s. This is useful for situations when a literal is needed to build the name of a function or macro.
pw_preprocessor/compiler.h#
Macros for compiler-specific features, such as attributes or builtins.
Modifying compiler diagnostics#
pw_preprocessor/compiler.h
provides macros for enabling or disabling
compiler diagnostics (warnings or errors) for sections of code.
PW_MODIFY_DIAGNOSTICS_PUSH
and PW_MODIFY_DIAGNOSTICS_POP
are used to turn off or on diagnostics (warnings or errors) for a section of
code. Use PW_MODIFY_DIAGNOSTICS_PUSH
, use
PW_MODIFY_DIAGNOSTIC
as many times as needed, then use
PW_MODIFY_DIAGNOSTICS_POP
to restore the previous settings.
PW_MODIFY_DIAGNOSTICS_PUSH();
PW_MODIFY_DIAGNOSTIC(ignored, "-Wunused-variable");
static int this_variable_is_never_used;
PW_MODIFY_DIAGNOSTICS_POP();
Tip
PW_MODIFY_DIAGNOSTIC
and related macros should rarely be used.
Whenever possible, fix the underlying issues about which the compiler is
warning, rather than silencing the diagnostics.
Integer with Overflow Checking#
pw_preprocessor/compiler.h
provides macros for performing arithmetic
operations and checking whether it overflowed.
API Reference#
-
PW_PACKED(declaration)#
Marks a struct or class as packed.
Use packed structs with extreme caution! Packed structs are rarely needed. Instead, define the struct and
static_assert
to verify that the size and alignement are as expected.Packed structs should only be used to avoid standard padding or to force unaligned members when describing in-memory or wire format data structures. Packed struct members should NOT be accessed directly because they may be unaligned. Instead,
memcpy
the fields into variables. For example:PW_PACKED(struct) PackedStruct { uint8_t a; uint32_t b; uint16_t c; }; void UsePackedStruct(const PackedStruct& packed_struct) { uint8_t a; uint32_t b; uint16_t c; std::memcpy(&a, &packed_struct.a, sizeof(a)); std::memcpy(&b, &packed_struct.b, sizeof(b)); std::memcpy(&c, &packed_struct.c, sizeof(c)); }
-
PW_USED#
Marks a function or object as used, ensuring code for it is generated.
-
PW_NO_PROLOGUE#
Prevents generation of a prologue or epilogue for a function. This is helpful when implementing the function in assembly.
-
PW_PRINTF_FORMAT(format_index, parameter_index)#
Marks that a function declaration takes a printf-style format string and variadic arguments. This allows the compiler to perform check the validity of the format string and arguments. This macro must only be on the function declaration, not the definition.
The format_index is index of the format string parameter and parameter_index is the starting index of the variadic arguments. Indices start at 1. For C++ class member functions, add one to the index to account for the implicit this parameter.
This example shows a function where the format string is argument 2 and the varargs start at argument 3.
int PrintfStyleFunction(char* buffer, const char* fmt, ...) PW_PRINTF_FORMAT(2,3); int PrintfStyleFunction(char* buffer, const char* fmt, ...) { ... implementation here ... }
-
PW_PLACE_IN_SECTION(name)#
Places a variable in the specified linker section.
-
PW_KEEP_IN_SECTION(name)#
Places a variable in the specified linker section and directs the compiler to keep the variable, even if it is not used. Depending on the linker options, the linker may still remove this section if it is not declared in the linker script and marked
KEEP
.
-
PW_NO_RETURN#
Indicate to the compiler that the annotated function won’t return. Example:
PW_NO_RETURN void HandleAssertFailure(ErrorCode error_code);
-
PW_NO_INLINE#
Prevents the compiler from inlining a fuction.
-
PW_UNREACHABLE#
Indicate to the compiler that the given section of code will not be reached. Example:
int main() { InitializeBoard(); vendor_StartScheduler(); // Note: vendor forgot noreturn attribute. PW_UNREACHABLE; }
-
PW_NO_SANITIZE(check)#
Indicate to a sanitizer compiler runtime to skip the named check in the associated function. Example:
uint32_t djb2(const void* buf, size_t len) PW_NO_SANITIZE("unsigned-integer-overflow") { uint32_t hash = 5381; const uint8_t* u8 = static_cast<const uint8_t*>(buf); for (size_t i = 0; i < len; ++i) { hash = (hash * 33) + u8[i]; /* hash * 33 + c */ } return hash; }
-
PW_HAVE_ATTRIBUTE(x)#
Wrapper around
__has_attribute
, which is defined by GCC 5+ and Clang and evaluates to a non zero constant integer if the attribute is supported or 0 if not.
-
PW_HAVE_CPP_ATTRIBUTE(x)#
A function-like feature checking macro that accepts C++11 style attributes. It is a wrapper around
__has_cpp_attribute
, which was introduced in the C++20 standard. It is supported by compilers even if C++20 is not in use. Evaluates to a non-zero constant integer if the C++ attribute is supported or 0 if not.This is a copy of
ABSL_HAVE_CPP_ATTRIBUTE
.
-
PW_MODIFY_DIAGNOSTICS_PUSH()#
Starts a new group of
PW_MODIFY_DIAGNOSTIC
statements. APW_MODIFY_DIAGNOSTICS_POP
statement must follow.
-
PW_MODIFY_DIAGNOSTICS_POP()#
PW_MODIFY_DIAGNOSTIC
statements since the most recentPW_MODIFY_DIAGNOSTICS_PUSH
no longer apply after this statement.
-
PW_MODIFY_DIAGNOSTIC(kind, option)#
Changes how a diagnostic (warning or error) is handled. Most commonly used to disable warnings.
PW_MODIFY_DIAGNOSTIC
should be used betweenPW_MODIFY_DIAGNOSTICS_PUSH
andPW_MODIFY_DIAGNOSTICS_POP
statements to avoid applying the modifications too broadly.kind
may bewarning
,error
, orignored
.
-
PW_MODIFY_DIAGNOSTIC_GCC(kind, option)#
Applies
PW_MODIFY_DIAGNOSTIC
only for GCC. This is useful for warnings that aren’t supported by or don’t need to be changed in other compilers.
-
PW_MODIFY_DIAGNOSTIC_CLANG(kind, option)#
Applies
PW_MODIFY_DIAGNOSTIC
only for Clang. This is useful for warnings that aren’t supported by or don’t need to be changed in other compilers.
-
PW_PRAGMA(contents)#
Expands to a
_Pragma
with the contents as a string._Pragma
must take a single string literal; this can be used to construct a_Pragma
argument.
-
PW_WEAK#
Marks a function or object as weak, allowing the definition to be overriden.
This can be useful when supporting third-party SDKs which may conditionally compile in code, for example:
PW_WEAK void SysTick_Handler(void) { // Default interrupt handler that might be overriden. }
-
PW_ALIAS(aliased_to)#
Marks a weak function as an alias to another, allowing the definition to be given a default and overriden.
This can be useful when supporting third-party SDKs which may conditionally compile in code, for example:
// Driver handler replaced with default unless overridden. void USART_DriverHandler(void) PW_ALIAS(DefaultDriverHandler);
-
PW_ATTRIBUTE_LIFETIME_BOUND#
PW_ATTRIBUTE_LIFETIME_BOUND
indicates that a resource owned by a function parameter or implicit object parameter is retained by the return value of the annotated function (or, for a parameter of a constructor, in the value of the constructed object). This attribute causes warnings to be produced if a temporary object does not live long enough.When applied to a reference parameter, the referenced object is assumed to be retained by the return value of the function. When applied to a non-reference parameter (for example, a pointer or a class type), all temporaries referenced by the parameter are assumed to be retained by the return value of the function.
See also the upstream documentation: https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
This is a copy of
ABSL_ATTRIBUTE_LIFETIME_BOUND
.
-
PW_ADD_OVERFLOW(a, b, out)#
PW_ADD_OVERFLOW
adds two integers while checking for overflow.Returns true if the result of
a + b
overflows the type ofout
; otherwise stores the result inout
and returns false.See also
PW_CHECK_ADD
.
-
PW_SUB_OVERFLOW(a, b, out)#
PW_SUB_OVERFLOW
subtracts an integer from another while checking for overflow.Returns true if the result of
a - b
overflows the type ofout
; otherwise stores the result inout
and returns false.See also
PW_CHECK_SUB
.
-
PW_MUL_OVERFLOW(a, b, out)#
PW_MUL_OVERFLOW
multiplies two integers while checking for overflow.Returns true if the result of
a * b
overflows the type ofout
; otherwise stores the result inout
and returns false.See also
PW_CHECK_MUL
.
-
PW_VA_OPT_SUPPORTED()#
Evaluates to 1 if
__VA_OPT__
is supported, regardless of the C or C++ standard in use.
pw_preprocessor/concat.h#
Defines the PW_CONCAT(...)
macro, which expands its arguments if they are
macros and token pastes the results. This can be used for building names of
classes, variables, macros, etc.
pw_preprocessor/util.h#
General purpose, useful macros.
PW_ARRAY_SIZE(array)
– calculates the size of a C arrayPW_STRINGIFY(...)
– expands its arguments as macros and converts them to a string literalPW_EXTERN_C
– declares a name to beextern "C"
in C++; expands to nothing in CPW_EXTERN_C_START
/PW_EXTERN_C_END
– declares anextern "C" { }
block in C++; expands to nothing in C
Zephyr#
To enable pw_preprocessor
for Zephyr add CONFIG_PIGWEED_PREPROCESSOR=y
to the project’s configuration.