Macros which help you describe your API to the compiler and/or static analyzers, giving your users helpful warnings when the misuse your API, without false positives.
Tell the compiler what you're doing (or what you want it to do) so compiled code is faster.
Macros which help convey versioning information, when symbols are are added and deprecated, and symbol visibility.
Macros to help make code useable from both C and C++.
Assorted macros which are useful, but don't really fit anywhere else.
Macros Hedley uses to detect the platform.
These macros are primarily intended to improve diagnostics (warnings and errors).
HEDLEY_ARRAY_PARAM(expr)
HEDLEY_WARN_UNUSED_RESULT
HEDLEY_SENTINEL(position)
HEDLEY_NO_RETURN
HEDLEY_FALL_THROUGH
HEDLEY_RETURNS_NON_NULL
HEDLEY_UNREACHABLE()
HEDLEY_UNREACHABLE_RETURN(value)
HEDLEY_ASSUME(expr)
HEDLEY_NON_NULL(...)
HEDLEY_PRINTF_FORMAT(string_idx, first_to_check)
HEDLEY_REQUIRE(expr)
HEDLEY_REQUIRE_MSG(expr, msg)
HEDLEY_FLAGS
HEDLEY_FLAGS_CAST
HEDLEY_ARRAY_PARAM(expr)
This macro is used to implement “conformant array parameters”. If you've never heard that term before, don't worry; not many people have! See CERT's C Coding Standard API05-C for information.
If the compiler is known to support conformant array
parameters, the macro will expand to param
.
Otherwise it will expand to nothing.
Note that you can only reference parameters which
come before the array; in the example, if
the n
and elems
parameters were
reversed this would likely result in an error.
Note that conformant array parameters may trigger a
warning on some compilers due to them thinking it is a
VLA. The
question of whether they really are VLAs
is ambiguous,
but they suffer from none of the drawbacks of variable
length arrays as array function parameters are demoted to
a plain pointer. For a way to generate an error when you
use a VLA without having the compiler emit a
diagnostic for conformant array parameters,
see HEDLEY_REQUIRE_CONSTEXPR()
void print_array(int x, int y, char* elems[HEDLEY_ARRAY_PARAM(x * y)]);
Platform | Version | Implementation |
---|---|---|
C | C99+ | Identity |
PGI | < 17.10 | |
PGI | 17.10+ in C99+ mode | Identity |
HEDLEY_WARN_UNUSED_RESULT
Function attribute which signals that the compiler should emit a diagnostic if the return value is discarded without being checked.
HEDLEY_WARN_UNUSED_RESULT bool do_something(void);
Platform | Version | Implementation |
---|---|---|
C | ||
C++ | C++17 | [[nodiscard]] |
GCC | 3.4.0+ | __attribute__((__warn_unused_result__)) |
Intel | 13.0+ | __attribute__((__warn_unused_result__)) |
TI | 8.0+ (7.3+ if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((__warn_unused_result__)) |
Oracle | 5.15 (ODS 12.6), C++-only | __attribute__((__warn_unused_result__)) |
PGI | 17.10 | __attribute__((__warn_unused_result__)) |
SAL (MSVC) | 2.0 (MSVC 11.0 / VS 2012) | _Check_return_ |
HEDLEY_SENTINEL(position)
Function is variadic, and must have an explicit NULL argument to indicate termination of the argument list.
HEDLEY_SENTINEL(0) void add_children(Context* ctx, ...);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 4.0.0+ | __attribute__((__sentinel__(position))) |
Intel | 16.0+ | __attribute__((__sentinel__(position))) |
ARM | 5.04+ | __attribute__((__sentinel__(position))) |
HEDLEY_NO_RETURN
Function is does not return. This is important for the compiler to be able to reason about later events; for example, if you call a no-return function if a variable is NULL, then the compiler can assume that the variable is non-NULL in the remainder of the function, which allows you to pass it to a function as a non-NULL parameter.
HEDLEY_NO_RETURN void log_fatal(const char* message);
Platform | Version | Implementation |
---|---|---|
C | C11+ | _Noreturn |
C++ | C++11+ | [[noreturn]] |
GCC | 3.2.0+ | __attribute__((__noreturn__)) |
Intel | 16.0+ | __attribute__((__noreturn__)) |
Oracle | 5.11+ (OSS 12.2) | __attribute__((__noreturn__)) |
ARM | 4.1+ | __attribute__((__noreturn__)) |
MSVC | 7.1+ (VS 2003) | __declspec(nereturn) |
TI | 8.0+ (7.3+ if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((__noreturn__) |
TI | 6.0+ (C++-only) | _Pragma("FUNC_NEVER_RETURNS;") |
IAR | 8.0+ | __noreturn |
HEDLEY_FALL_THROUGH
Explicitly tell the compiler to fall through a case in the switch statement. Without this, some compilers may think you accidentally omitted a "break;" and emit a diagnostic.
switch (foo) { case FOO: handle_foo(); HEDLEY_FALL_THROUGH; case BAR: handle_bar(); break; }
Platform | Version | Implementation |
---|---|---|
C | ||
C++ | C++17+ | [[fallthrough]] |
Clang++ | [[clang::fallthrough]] |
|
GCC | 7+ (in C++11 - C++14 mode) | [[gnu::fallthrough]] |
GCC | 7+ | __attribute__((__fallthrough__)) |
SAL | defined(_fallthrough) (2.0) |
_fallthrough |
HEDLEY_RETURNS_NON_NULL
The function will alwoys return a non-null value.
This may allow the compiler to skip some null-pointer checks.
HEDLEY_RETURNS_NON_NULL void* foo(void);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 4.9+ | __attribute__((__returns_nonnull__)) |
SAL | defined(_Ret_notnull_) (2.0) |
_Ret_notnull_ |
HEDLEY_UNREACHABLE()
Inform the compiler/analyzer that the code should never be reached (even with invalid input).
switch (foo) { case BAR: do_something(); break; case BAZ: do_something_else(); break; default: HEDLEY_UNREACHABLE(); break; }
Platform | Version | Implementation |
---|---|---|
GCC | 4.5.0+ | __builtin_unreachable() |
Intel | 16.0+ | __builtin_unreachable() |
MSVC | 7.1+ (VS 2003) | __assume(0) |
TI | 6.0+ (C mode) | _nassert(0) |
TI | 6.0+ (C++ mode) | std::_nassert(0) |
C | C89+ (with assert.h) | assert(0) |
C | C89+ (with stdlib.h) | abort() |
HEDLEY_UNREACHABLE_RETURN()
Inform the compiler/analyzer that the code should never be reached or, for compilers which don't provide a way to provide such information, return a value.
static int handle_code(enum Foo code) { switch (code) { case FOO_BAR: case FOO_BAZ: case FOO_QUX: return 0; } HEDLEY_UNREACHABLE_RETURN(0); }
Platform | Version | Implementation |
---|---|---|
GCC | 4.5.0+ | __builtin_unreachable() |
Intel | 16.0+ | __builtin_unreachable() |
MSVC | 7.1+ (VS 2003) | __assume(0) |
C | return value |
HEDLEY_ASSUME(expr)
Inform the compiler/analyzer that the provided expression should always evaluate to a non-false value.
Note that,
unlike HEDLEY_PREDICT_TRUE
and HEDLEY_LIKELY
,
the compiler is free to assume that the
expression never evaluates to true and therefore
can elide code paths where it does evaluate to true. In
other words, this is more similar
to HEDLEY_UNREACHABLE()
,
and many implementations of this macro do actually
use __builtin_unreachable
and similar
constructs.
void sum(int x, int s[HEDLEY_ARRAY_PARAM(x), int a[HEDLEY_ARRAY_PARAM(x), int b[HEDLEY_ARRAY_PARAM(x)) { HEDLEY_ASSUME((x % 8) == 0); for (int i = 0 ; i < x ; i++) { s[i] = a[i] + b[i]; } }
HEDLEY_NON_NULL(...)
List parameters which must never be NULL (for example, because they are unconditionally dereferenced in the function body).
HEDLEY_NON_NULL(1,3) void do_something(Context* ctx_cant_be_null, Foo* maybe_null, Bar* cant_be_null);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 3.3.0+ | __attribute__((__nonnull__(__VA_ARGS__))) |
Intel | 16.0+ | __attribute__((__nonnull__(__VA_ARGS__))) |
ARM | 4.1+ | __attribute__((__nonnull__(__VA_ARGS__))) |
MSVC |
HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)
Inform the compiler/analyzer that the function takes a printf-style format string, so that it can check the arguments.
HEDLEY_PRINTF_FORMAT(2,3) void print_warning(Context* ctx, const char* fmt, ...);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 3.1.0+ | __attribute__((format(__printf__, string_idx, first_to_check))) |
GCC | 4.4.0+ + MingW + !defined(__USE_MINGW_ANSI_STDIO) | __attribute__((format(ms_printf, string_idx, first_to_check))) |
GCC | 4.4.0+ + MingW + defined(__USE_MINGW_ANSI_STDIO) | __attribute__((format(gnu_printf, string_idx, first_to_check))) |
Intel | 16.0+ | __attribute__((format(__printf__, string_idx, first_to_check))) |
ARM | 5.06+ | __attribute__((format(__printf__, string_idx, first_to_check))) |
TI | 8.0+ (7.3+ if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((format(__printf__, string_idx, first_to_check))) |
Note that there
is _Printf_format_string_
SAL macro, but it must be
placed in a different location and cannot serve as an
implementation for HEDLEY_PRINTF_FORMAT
.
HEDLEY_REQUIRE(expr)
Compile-time precondition.
int foo(int a, int b) HEDLEY_REQUIRE(a < b);
Platform | Version | Implementation |
---|---|---|
clang | __has_attribute(diagnose_if) |
__attribute__((__diagnose_if__(expr, #expr, "error"))) |
HEDLEY_REQUIRE_MSG(expr, msg)
Compile-time precondition with user-specified error message.
int foo(int a, int b) HEDLEY_REQUIRE(a < b, "a must be less than b");
Platform | Version | Implementation |
---|---|---|
clang | __has_attribute(diagnose_if) |
__attribute__((__diagnose_if__(expr, msg, "error"))) |
HEDLEY_FLAGS
Annotate an enumeration as containing bit flags.
enum Foo { FOO_BAR = 1 << 0, FOO_BAZ = 1 << 1, FOO_QUX = 1 << 2 } HEDLEY_FLAGS;
Platform | Version | Implementation |
---|---|---|
clang | __has_attribute(flag_enum) |
__attribute__((__flag_enum__)) |
HEDLEY_FLAGS_CAST
Cast to a flags enumeration type.
This will attempt to quiet any warnings the C/C++ compiler may emit because you are casting a value which may not appear in the enumeration.
const enum Foo foo = HEDLEY_FLAGS_CAST(enum Foo, FOO_BAR | FOO_BAZ);
Macros which are intended mostly to provide hints for optimizing compilers.
HEDLEY_LIKELY(expr)
HEDLEY_UNLIKELY(expr)
HEDLEY_MALLOC
HEDLEY_PURE
HEDLEY_CONST
HEDLEY_RESTRICT
HEDLEY_INLINE
HEDLEY_ALWAYS_INLINE
HEDLEY_NEVER_INLINE
HEDLEY_NO_THROW
HEDLEY_NO_ESCAPE
HEDLEY_LIKELY(expr)
Marks an expression as likely to evaluate to true (non-zero).
if(HEDLEY_LIKELY(foo != NULL)) { do_something_with_foo(foo); return true; } else { return false; }
Platform | Version | Implementation |
---|---|---|
GCC | 3.0.0+ | __builtin_expect(!!(expr), 1) |
Intel | 16.0+ | __builtin_expect(!!(expr), 1) |
Oracle | 5.12+ (Solaris Studio 12.3+) | __builtin_expect(!!(expr), 1) |
ARM | 4.1+ | __builtin_expect(!!(expr), 1) |
TI | 7.3+ | __builtin_expect(!!(expr), 1) |
C | Any | (!!(expr)) |
HEDLEY_UNLIKELY
Marks an expression as likely to evaluate to false (zero).
Context* ctx = malloc(sizeof(Context)); if(HEDLEY_UNLIKELY(ctx == NULL)) return ENOMEM; ctx->foo = bar;
Platform | Version | Implementation |
---|---|---|
GCC | 3.0.0+ | __builtin_expect(!!(expr), 0) |
Intel | 16.0+ | __builtin_expect(!!(expr), 0) |
Oracle | 5.12+ (Solaris Studio 12.3+) | __builtin_expect(!!(expr), 0) |
ARM | 4.1+ | __builtin_expect(!!(expr), 0) |
TI | 7.3+ | __builtin_expect(!!(expr), 0) |
C | Any | (!!(expr)) |
Note: assertion functions are typically already annotated
with something like this. You probably shouldn't be
adding HEDLEY_UNLIKELY
to all your
assertions.
HEDLEY_PREDICT
Tell the compiler to expect an expression to evaluate to a supplied value with a specified probability.
if (HEDLEY_PREDICT(foo, 1, 0.67)) { do_things(); }
HEDLEY_PREDICT_TRUE
Tell the compiler to expect an expression to evaluate to TRUE with a provided probability.
if (HEDLEY_PREDICT_TRUE(foo, 0.67)) { do_things(); }
This macro is similar
to HEDLEY_LIKELY
,
but with a stated probability.
HEDLEY_PREDICT_FALSE
Tell the compiler to expect an expression to evaluate to FALSE with a provided probability.
if (HEDLEY_PREDICT_FALSE(foo, 0.67)) { do_things(); }
This macro is similar
to HEDLEY_UNLIKELY
,
but with a stated probability.
if (HEDLEY_PREDICT_FALSE(foo, 1, 0.67)) { do_things(); }
HEDLEY_UNPREDICTABLE
Tell the compiler to expect an expression to evaluate to a supplied value with a specified probability.
if (HEDLEY_UNPREDICTABLE(foo)) { do_things(); }
HEDLEY_MALLOC
Inform the compiler that the pointer returned by this function does not alias any other pointer, and that there are no pointers to valid objects in the storage pointed to.
HEDLEY_MALLOC uint8_t* create_buffer(void);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 3.1.0+ | __attribute__((__malloc__)) |
Intel | 16.0+ | __attribute__((__malloc__)) |
Oracle | 5.11+ | __attribute__((__malloc__)) |
ARM | 4.1+ | __attribute__((__malloc__)) |
MSVC | 14+ (VS 2005) | __declspec(restrict) |
TI | 8.0+ (7.3+ if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((__malloc__)) |
HEDLEY_PURE
The function has no side-effects, and the return value depends only on the parameters and/or global variables.
HEDLEY_PURE bool multiply(int* product, int a, int b);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 4.3.0+ | __attribute__((__pure__)) |
Intel | 16.0+ | __attribute__((__pure__)) |
Oracle | 5.11+ | __attribute__((__pure__)) |
ARM | 4.1+ | __attribute__((__pure__)) |
TI | 8.0+ (7.3+ if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((__pure__)) |
TI | 6.0+ (C++-only) | _Pragma("FUNC_IS_PURE;") |
HEDLEY_CONST
The function has no side-effects, and the return value depends only on the parameters.
Note that pointer arguments are not allowed.
HEDLEY_CONST int multiply(int a, int b);
Platform | Version | Implementation |
---|---|---|
GCC | 2.5.0+ | __attribute__((__const__)) |
Intel | 16.0+ | __attribute__((__const__)) |
Oracle | 5.11+ | __attribute__((__const__)) |
ARM | 4.1+ | __attribute__((__const__)) |
TI | 8.0+ (7.3+ if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((__const__)) |
Other | HEDLEY_PURE |
HEDLEY_RESTRICT
The pointer is not aliased.
void do_something(int* HEDLEY_RESTRICT a, int* HEDLEY_RESTRICT b);
Platform | Version | Implementation |
---|---|---|
C | C99+ | restrict |
GCC | 3.1.0+ | __restrict |
Intel | 16.0+ | __restrict |
ARM | 4.1+ | __restrict |
MSVC | 14+ (VS 2005) | __restrict |
ODS | 5.3+ (Forte Developer 6) in C mode | _Restrict |
ODS | 5.14+ (Solaris Studio 12.5) in C++ mode | __restrict |
TI | 7.3+ | __restrict |
IAR | 8.0+ | __restrict |
HEDLEY_INLINE
Quoting from the C99 standard (§ 6.7.4.5):
Making a function an inline function suggests that calls to the function be as fast as possible. The extent to which such suggestions are effective is implementation-defined.
HEDLEY_INLINE void do_something_quickly(void);
Platform | Version | Implementation |
---|---|---|
C | C99+ | inline |
GCC | 4.3.0+ | __inline__ |
ARM | 6.2+ | __inline__ |
ARM | 4.1+ | __inline |
MSVC | 12+ (VS 6) | __inline |
HEDLEY_ALWAYS_INLINE
Tell the compiler to always inline the function, even if it thinks doing so would be a bad idea.
HEDLEY_ALWAYS_INLINE void do_something_quickly(void);
Platform | Version | Implementation |
---|---|---|
Fallback | HEDLEY_INLINE |
|
GCC | 4.0.0+ | __attribute__((__always_inline__)) HEDLEY_INLINE |
Intel | 16.0+ | __attribute__((__always_inline__)) HEDLEY_INLINE |
Oracle | 5.11+ (ODS 12.2) | __attribute__((__always_inline__)) HEDLEY_INLINE |
ARM | 4.1+ | __attribute__((__always_inline__)) HEDLEY_INLINE |
IBM | 10.1.0++ | __attribute__((__always_inline__)) HEDLEY_INLINE |
MSVC | 12+ (VS 6) | __forceinline |
TI | 8.0+ (7.3+ if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((__always_inline__)) |
TI | 7.0+ (C++-only) | _Pragma("FUNC_ALWAYS_INLINE;") |
IAR | 8.0+ | _Pragma("inline=forced") |
HEDLEY_NEVER_INLINE
Never inline the function, even if the compiler thinks doing so would be a good idea.
HEDLEY_NEVER_INLINE void do_something(void);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 4.0.0+ | __attribute__((__noinline__)) |
Intel | 16.0+ | __attribute__((__noinline__)) |
Oracle | 5.11+ (ODS 12.2) | __attribute__((__noinline__)) |
ARM | 4.1+ | __attribute__((__noinline__)) |
MSVC | 13.10+ (VS 7.1) | __noinline |
PGI | 10.2+ | _Pragma"noinline" |
TI | 8.0+ (7.3+ if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((__noinline__)) |
TI | 6.0+ (C++-only) | _Pragma("FUNC_CANNOT_INLINE;") |
IAR | 8.0+ | _Pragma("inline=never") |
HEDLEY_NO_THROW
Tell the compiler that the function will never throw a C++ exception. Note that this can improve performance even in C mode. Use only if you're sure your function will never call a function which throws a C++ exception, even indirectly.
HEDLEY_NO_THROW void do_something(void);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 3.3.0+ | __attribute__((__nothrow__)) |
Intel | 16.0+ | __attribute__((__nothrow__)) |
MSVC | 13.10+ (VS 7.1) | __declspec(nothrow) |
ARM | 4.1+ | __declspec(nothrow) |
HEDLEY_NO_ESCAPE
Tell the compiler that the pointer will not escape the
function call. For more information, see the
documentation
for clang's noescape
attribute.
void foo(HEDLEY_NO_ESCAPE Bar* baz);
Platform | Version | Implementation |
---|---|---|
C | ||
clang | __has_attribute(noesecape) (clang 6.0+) |
__attribute__((__noescape__)) |
Macros which are used to help manage APIs.
HEDLEY_VERSION_ENCODE(major,minor,revision)
HEDLEY_VERSION_DECODE_MAJOR(version)
HEDLEY_VERSION_DECODE_MINOR(version)
HEDLEY_VERSION_DECODE_REVISION(version)
HEDLEY_DEPRECATED(since)
HEDLEY_DEPRECATED_FOR(since, replacement)
HEDLEY_UNAVAILABLE(available_since)
HEDLEY_PRIVATE
HEDLEY_PUBLIC
HEDLEY_IMPORT
HEDLEY_VERSION_ENCODE(major,minor,revision)
Encode a major version number, minor version number, and revision number into a single number.
Up to 1000 releases (0-999) are supported for each section (major, minor, revision).
HEDLEY_VERSION_ENCODE(1,2,3)
Platform | Version | Implementation |
---|---|---|
C | (((major) * 1000000) + ((minor) * 1000) + (revision)) |
HEDLEY_VERSION_DECODE_MAJOR(version)
Decodes a version number (encoded
with HEDLEY_VERSION_ENCODE
), returning the
major version number.
Platform | Version | Implementation |
---|---|---|
C | ((version) / 1000000) |
HEDLEY_VERSION_DECODE_MINOR(version)
Decodes a version number (encoded
with HEDLEY_VERSION_ENCODE
), returning the
minor version number.
Platform | Version | Implementation |
---|---|---|
C | (((version) % 1000000) / 1000) |
HEDLEY_VERSION_DECODE_REVISION(version)
Decodes a version number (encoded
with HEDLEY_VERSION_ENCODE
), returning the
revision number.
Platform | Version | Implementation |
---|---|---|
C | ((version) % 1000) |
HEDLEY_DEPRECATED(since)
The symbol is deprecated and should not be used in new code.
HEDLEY_DEPRECATED(4.2) void do_something(void);
Platform | Version | Implementation |
---|---|---|
C | ||
C++ | C++14 | [[deprecated("Since " #since)]] |
Clang | __attribute__((__deprecated__("Since " #since))) |
|
GCC | 4.5.0+ | __attribute__((__deprecated__("Since " #since))) |
GCC | 4.0.0+ | __attribute__((deprecated)) |
Intel | 16.0+ | __attribute__((__deprecated__("Since " #since))) |
ARM | 5.06+ | __attribute__((__deprecated__("Since " #since))) |
ARM | 4.1+ | __attribute__((deprecated)) |
MSVC | 14.0+ (VS 2005) | __declspec(deprecated("Since " # since)) |
MSVC | 13.10+ (VS 2003) | __declspec(deprecated) |
TI | 7.3.0+ (if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((deprecated("Since " #since))) |
TI | 8.0+ | __attribute__((deprecated("Since " #since))) |
IAR | 8.0+ | _Pragma("deprecated") |
HEDLEY_DEPRECATED_FOR(since, replacement)
The symbol is deprecated and should not be used in new code; replacement should be used instead.
HEDLEY_DEPRECATED_FOR(4.2, do_something_better) void do_something(void);
Platform | Version | Implementation |
---|---|---|
C | ||
C++ | C++14 | [[deprecated("Since " #since "; use " #replacement)]] |
GCC | 4.5.0+ | __attribute__((deprecated("Since " #since "; use " #replacement))) |
GCC | 4.0.0+ | __attribute__((deprecated)) |
Intel | 16.0+ | __attribute__((deprecated("Since " #since "; use " #replacement))) |
ARM | 5.06+ | __attribute__((deprecated("Since " #since "; use " #replacement))) |
ARM | 4.1+ | __attribute__((deprecated)) |
MSVC | 14.0+ (VS 2005) | __declspec(deprecated("Since " # since "; use " #replacement)) |
MSVC | 13.10+ (VS 2003) | __declspec(deprecated) |
TI | 7.3.0+ (if defined(__TI_GNU_ATTRIBUTE_SUPPORT__) ) |
__attribute__((deprecated("Since " #since "; use " #replacement))) |
TI | 8.0+ | __attribute__((deprecated("Since " #since "; use " #replacement))) |
IAR | 8.0+ | _Pragma("deprecated") |
HEDLEY_UNAVAILABLE(available_since)
The symbol is not available in the version of the API in use. Note that this macro is not meant to be used directly; see the “Versioning” section of the Hedley User Guide for an explanation.
HEDLEY_UNAVAILABLE(4.2) void do_something(void);
Platform | Version | Implementation |
---|---|---|
C | ||
GCC | 4.3.0+ | __attribute__((warning("Not available until " #available_since))) |
HEDLEY_PRIVATE
The symbol should not be exposed publicly; this should never be used in a public header.
HEDLEY_PRIVATE void do_something(void);
HEDLEY_PUBLIC
The symbol should be exposed publicly. Note that this macro is not meant to be used directly; see the “Versioning” section of the Hedley User Guide for an explanation.
HEDLEY_IMPORT
The symbol is defined in another library. Note that this macro is not meant to be used directly; see the “Versioning” section of the Hedley User Guide for an explanation.
HEDLEY_BEGIN_C_DECLS
Tell a C++ compiler to begin use C linkage for the following symbols.
HEDLEY_BEGIN_C_DECLS void do_something(void); void do_something_else(void); HEDLEY_END_C_DECLS
Platform | Version | Implementation |
---|---|---|
C | ||
C++ | extern "C" { |
HEDLEY_END_C_DECLS
Tell a C++ compiler to stop using C linkage.
HEDLEY_END_C_DECLS void do_something(void);
Platform | Version | Implementation |
---|---|---|
C | ||
C++ | } |
HEDLEY_C_DECL
Tell a C++ compiler to use C linkage for the symbol.
HEDLEY_C_DECL void do_something(void);
Platform | Version | Implementation |
---|---|---|
C | ||
C++ | extern "C" |
HEDLEY_CONST_CAST(T,expr)
Cast to T
, possibly removing const
type qualifiers.
This is primarily useful for code which should be usable
from both C and C++ (e.g. shared headers), but can
also be useful for eliminating some warnings from some C
compilers in certain configurations (GCC/clang/ICC
with -Wcast-qual
).
const char* foo = "Hello, world!"; char* bar = HEDLEY_CONST_CAST(char*, foo);
Platform | Version | Implementation |
---|---|---|
C++ | const_cast<T>(expr) |
|
GCC | 3.0+ | (__extension__ ({
HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
((T) (expr));
HEDLEY_DIAGNOSTIC_POP
}) |
clang | (__extension__ ({
HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
((T) (expr));
HEDLEY_DIAGNOSTIC_POP
}) |
|
ICC | 17+ | (__extension__ ({
HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
((T) (expr));
HEDLEY_DIAGNOSTIC_POP
}) |
C | ((T) (expr)) |
HEDLEY_REINTERPRET_CAST(T,expr)
Reinterpret one type as another.
This is primarily useful for code which should be usable from both C and C++ (e.g. shared headers).
uint8_t foo[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; uint64_t bar = *HEDLEY_REINTERPRET_CAST(uint64_t*, foo);
Platform | Version | Implementation |
---|---|---|
C++ | reinterpret_cast<T>(expr) |
|
C | (*((T*) &(expr))) |
HEDLEY_STATIC_CAST(T,expr)
Cast from one type to another.
This is primarily useful for code which should be usable
from both C and C++ (e.g. shared headers) where in
C++ code you would use a static_cast
. Some
compilers (such as clang with -Wold-style-cast
)
will emit a diagnostic if you attempt to use a C-style cast
in C++ code.
int foo = 1729; unsigned int bar = HEDLEY_STATIC_CAST(unsigned int, foo);
Platform | Version | Implementation |
---|---|---|
C++ | static_cast<T>(expr) |
|
C | ((T) (expr)) |
HEDLEY_CPP_CAST(T,expr)
Create a cast in C++, but rely on C implicit conversions in C.
This macro is especially useful in conjunction with HEDLEY_FLAGS
, since a
cast in C will eliminate warnings which may be desirable, but no cast in C++ may result
in warnings and/or errors.
enum Foo foo = HEDLEY_CPP_CAST(enum Foo, FOO_BAR | FOO_BAZ);
Platform | Version | Implementation |
---|---|---|
C | ||
C++ | static_cast<T>(expr) |
HEDLEY_STATIC_ASSERT(expr)
Perform a compile-time assertion; note that the it must be possible to evaluate expr at compile-time.
HEDLEY_STATIC_ASSERT(sizeof(int) >= 4, "int must be at least 32-bits");
Platform | Version | Implementation |
---|---|---|
C | ||
C | C11+ | _Static_assert(expr, message) |
GCC | 4.6.0+ | _Static_assert(expr, message) |
MSVC | 16.0+ (VS 2010) | static_assert(expr, message) |
Pádraig Brady has
some additional
macros, but they don't work in all situations; for
example, some versions don't work in the global scope,
others don't work in the middle of a function, etc.
However, if you're careful about what version you use and
where, it's possible to cover more cases
than HEDLEY_STATIC_ASSERT
.
HEDLEY_DIAGNOSTIC_PUSH
Remember the current state of the compiler's diagnostics.
Warning: GCC prior to 4.6 requires this annotation be placed outside of any functions.
HEDLEY_DEPRECATED void foo(void); HEDLEY_DIAGNOSTIC_PUSH HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED static void bar(void) { foo(); } HEDLEY_DIAGNOSTIC_POP
Platform | Version | Implementation |
---|---|---|
C | ||
clang | _Pragma("clang diagnostic push") |
|
Intel | 16.0+ | _Pragma("warning(push)") |
GCC | 4.6.0+ | Pragma("GCC diagnostic push") |
MSVC | 15.0+ (VS 2010) | __pragma(warning(push)) |
ARM | 5.06+ | _Pragma("push") |
TI | 8.1+ | _Pragma("diag_push") |
HEDLEY_DIAGNOSTIC_POP
Return the state of the compiler's diagnostics to the value from the last push.
Warning: GCC prior to 4.6 requires this annotation be placed outside of any functions.
HEDLEY_DEPRECATED void foo(void); HEDLEY_DIAGNOSTIC_PUSH HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED static void bar(void) { foo(); } HEDLEY_DIAGNOSTIC_POP
Platform | Version | Implementation |
---|---|---|
C | ||
clang | _Pragma("clang diagnostic push") |
|
Intel | 16.0+ | _Pragma("warning(push)") |
GCC | 4.6.0+ | Pragma("GCC diagnostic push") |
MSVC | 15.0+ (VS 2010) | __pragma(warning(push)) |
ARM | 5.06+ | _Pragma("pop") |
TI | 8.0+ | _Pragma("diag_pop") |
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
Do not emit warnings when using deprecated symbols.
Warning: GCC prior to 4.6 requires this annotation be placed outside of any functions.
HEDLEY_DEPRECATED void foo(void); HEDLEY_DIAGNOSTIC_PUSH HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED static void bar(void) { foo(); } HEDLEY_DIAGNOSTIC_POP
Platform | Version | Implementation |
---|---|---|
C | ||
clang | _Pragma("clang diagnostic ignored \"-Wdeprecated\"") |
|
Intel | 16.0+ | _Pragma("warning(disable:1478)") |
GCC | 4.6.0+ | _Pragma("GCC diagnostic ignored \"-Wdeprecated\"") |
MSVC | 15.0+ (VS 2010) | __pragma(warning(disable:4996)) |
Oracle | 12.4+ in C++ mode | _Pragma("error_messages(off,symdeprecated,symdeprecated2)") |
Oracle | 12.4+ in C mode | _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") |
IAR | 8.0+ | _Pragma("diag_duppress=Pe1444,Pe1215") |
HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
Do not emit warnings when using deprecated symbols.
Warning: GCC prior to 4.6 requires this annotation be placed outside of any functions.
HEDLEY_DIAGNOSTIC_PUSH HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #pragma foo bar hEDLEY_DIAGNOSTIC_POP
Platform | Version | Implementation |
---|---|---|
C | ||
clang | _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") |
|
Intel | 16.0+ | _Pragma("warning(disable:161)") |
GCC | 4.6.0+ | _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") |
MSVC | 15.0+ (VS 2010) | __pragma(warning(disable:4068)) |
TI | 8.0+ | _Pragma("diag_suppress 163") |
IAR | 8.0+ | _Pragma("diag_duppress=Pe161") |
HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
Do not emit warnings about discarding type qualifiers when casting.
You probably want to
use HEDLEY_CONST_CAST
instead of using this macro directly.
Warning: GCC prior to 4.6 requires this annotation be placed outside of any functions.
const char* foo = "Hello, world!"; HEDLEY_DIAGNOSTIC_PUSH HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL char* bar = foo; hEDLEY_DIAGNOSTIC_POP
Platform | Version | Implementation |
---|---|---|
C | ||
clang | _Pragma("clang diagnostic ignored \"-Wcast-qual\"") |
|
Intel | 17.0+ | _Pragma("warning(disable:2203)") |
GCC | 3.0.0+ | _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") |
HEDLEY_PRAGMA(value)
Do not emit warnings when using deprecated symbols.
HEDLEY_PRAGMA(omp simd)
Platform | Version | Implementation |
---|---|---|
C | ||
C | C99+ | _Pragma(#value) |
MSVC | 15.0+ (VS 2010) | __pragma(value) |
HEDLEY_STRINGIFY(value)
Convert value to a string. value can be a preprocessor macro.
#define BAR bar const char* foo_bar(void) { return HEDLEY_STRINGIFY(BAR); }
HEDLEY_CONCAT(a,b)
Concatenate two values.
#define PREFIX foo_ #define BAR bar const char* foo_bar(void) { return HEDLEY_STRINGIFY(BAR); } int main(void) { printf("%s\n", HEDLEY_CONCAT(PREFIX, BAR)()); return 0; }
HEDLEY_IS_CONSTANT(expr)
Determine if an expression is known at compile time to be constant.
This macro is intended to be used for choosing between a code path which can be constant-folded if the value of the expression is known at compile time but would be slow at runtime and a path which is unknown to the compiler but fast at runtime.
For compilers which do not provide a way to determine this, 0 is returned unconditionally.
#define foo(bar) (HEDLEY_IS_CONSTANT(bar) ? baz(bar) : qux(bar))
HEDLEY_REQUIRE_CONSTEXPR(expr)
If expr is not an integer constant expression, return -1. If it is an ICE, or the compiler doesn't provide a way to determine whether it is, return expr.
This is intended primarily to provide a way to make sure you don't unintentionally create a VLA.
It may help to think of this macro as a more portable
version of the -Werror=vla
compiler flag (for
GCC and clang) with the added benefit that it will not
trigger a diagnostic for conformant array parameters
(see HEDLEY_ARRAY_PARAM(expr)
.
It's worth noting that this is not the same
as (HEDLEY_IS_CONSTANT(expr) ? (expr) : -1)
;
this macro attempts to verify that expr is an
integer constant expression as defined by the C standard,
whereas HEDLEY_IS_CONSTANT
tries to determine
if the value is known by the compiler at compile time
(though it does fall back on checking for
an ICE on some compilers).
char foo[HEDLEY_REQUIRE_CONSTEXPR()];
HEDLEY_CONSTEXPR(expr)
The C++ constexpr
qualifier if it is supported.
HEDLEY_CONSTEXPR static int foo(int bar) { /* Do stuff */ }
HEDLEY_NULL
For C++11+, this macro is defined to nullptr
.
Otherwise, it is NULL
.
This macro is used to help maintain portability between C,
C++ < C++11, and C++11+. If your project requires C++11,
you should probably be using nullptr
directly.
If you don't care about C++11 and want to stick to C++98 or
C, you should be using NULL
. Even if you do
want your code to be portable across C++11, you can still
generally just use NULL
unless you're worried
about clang's -Wzero-as-null-pointer-constant
diagnostic (which is disabled by default but enabled
by -Weverything
).
Basically, you should only use this if you understand
exactly what it does and why (i.e., the difference
between nullptr
and NULL
), and
want to make absolutely certain people can compile your code
in diverse environments without any warnings even
when very aggressive warning settings are being
used.
foo(HEDLEY_NULL);
HEDLEY_MESSAGE(msg)
Emit a non-fatal compile-time informational message.
HEDLEY_MESSAGE("Message goes here")
GCC | 4.4+ | _Pragma("message msg") |
---|---|---|
ICC | 16+ | _Pragma("message msg") |
Clang | HEDLEY_DIAGNOSTIC_PUSH \ |
|
MSVC | 15.0+ (VS 2010) | __pragma(message(msg)) |
IAR | 8.0+ | _Pragma("message(msg)") |
HEDLEY_WARNING(msg)
Emit a compile-time warning. If compiling with fatal warnings (e.g., -Wall on GCC, or /WX on MSVC), these may be treated as fatal.
#if !defined(HAVE_PTHREADS) && !defined(_WIN32) HEDLEY_WARNING("No mutex implementation found; code will not be thread-safe.") #endif
Platform | Version | Implementation |
---|---|---|
GCC | 4.8+ | _Pragma("GCC warning msg") |
ICC | 16+ | _Pragma("GCC warning msg") |
Cray | 5.0+ | _Pragma("_CRI message msg") |
Fallback | HEDLEY_MESSAGE(msg) |
There are really intended for use internally by Hedley, but they can be useful for other users.
There are basically four sub-categories of platform detection macros in Hedley:
These macros defined only if the compiler in question is
in use (e.g., HEDLEY_PGI_VERSION is only
defined when using the PGI compiler). When they are
defined, they are defined to the version of the compiler
currently in use, encoded
with HEDLEY_VERSION_ENCODE()
.
This provides a uniform way to check the if a specific compiler is in use, as well as determine the version.
Note that the GCC and GNUC macros are different. Many compilers masquerade as GCC (by defining __GNUC__, __GNUC_MINOR__, and __GNUC_PATCHLEVEL__, but often do not implement all the features that the version of GCC they pretend to be supports. To work around this, the HEDLEY_GCC_VERSION macro is only defined for GCC, whereas HEDLEY_GNUC_VERSION will be defined whenever a compiler defines __GNUC__.
#if defined(HEDLEY_PGI_VERSION) printf("PGI %d.%d.%d\n", HEDLEY_VERSION_DECODE_MAJOR(HEDLEY_PGI_VERSION), HEDLEY_VERSION_DECODE_MINOR(HEDLEY_PGI_VERSION), HEDLEY_VERSION_DECODE_REVISION(HEDLEY_PGI_VERSION)); #endif
HEDLEY_GNUC_VERSION
HEDLEY_MSVC_VERSION
HEDLEY_INTEL_VERSION
HEDLEY_PGI_VERSION
HEDLEY_SUNPRO_VERSION
HEDLEY_EMSCRIPTEN_VERSION
HEDLEY_ARM_VERSION
HEDLEY_IBM_VERSION
HEDLEY_TI_VERSION
HEDLEY_CRAY_VERSION
HEDLEY_IAR_VERSION
HEDLEY_TINYC_VERSION
HEDLEY_DMC_VERSION
HEDLEY_GCC_VERSION
For each compiler for which there is a HEDLEY_*_VERSION macro, there is a HEDLEY_*_VERSION_CHECK(major,minor,revision) macro. These macros are always defined, and will return true (1) if the current compiler corresponds to the macro name, and the compiler version is greater than or equal to the provided values.
This provides a convenient way to check for features based on the version number. For example:
#if HEDLEY_MSVC_VERSION_CHECK(13,10,0) __declspec(deprecated) #endif
Of course, in this case you should probably be
using HEDLEY_DEPRECATED
instead.
HEDLEY_GNUC_VERSION_CHECK(major,minor,revision)
HEDLEY_MSVC_VERSION_CHECK(major,minor,revision)
HEDLEY_INTEL_VERSION_CHECK(major,minor,revision)
HEDLEY_PGI_VERSION_CHECK(major,minor,revision)
HEDLEY_SUNPRO_VERSION_CHECK(major,minor,revision)
HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,revision)
HEDLEY_ARM_VERSION_CHECK(major,minor,revision)
HEDLEY_IBM_VERSION_CHECK(major,minor,revision)
HEDLEY_TI_VERSION_CHECK(major,minor,revision)
HEDLEY_CRAY_VERSION_CHECK(major,minor,revision)
HEDLEY_IAR_VERSION_CHECK(major,minor,revision)
HEDLEY_TINYC_VERSION_CHECK(major,minor,revision)
HEDLEY_DMC_VERSION_CHECK(major,minor,revision)
HEDLEY_GCC_VERSION_CHECK(major,minor,revision)
Clang introduced an easier way to detect different features which doesn't rely on knowledge of the version number it first appeared in. Not only is this the preferred method for checking for features in clang, it's pretty much the only way! Apple's version of clang uses a completely different versioning scheme, and they set the __clang__ macros to their values.
Hedley wraps these macros with versions that are always defined:
HEDLEY_HAS_ATTRIBUTE(attribute)
HEDLEY_HAS_CPP_ATTRIBUTE(cpp_attribute)
HEDLEY_HAS_CPP_ATTRIBUTES_NS(ns,cpp_attribute)
HEDLEY_HAS_BUILTIN(builtin)
HEDLEY_HAS_FEATURE(feature)
HEDLEY_HAS_EXTENSION(extension)
HEDLEY_HAS_DECLSPEC_ATTRIBUTE(declspec_attribute)
HEDLEY_HAS_WARNING(warning)
#if HEDLEY_HAS_ATTRIBUTE(noinline) __attribute__((__noinline__)) #endif
Many clang-based compilers implement these macros, including:
Additionally, some non-clang-based compilers support a subset of the macros, including Oracle Developer Studio.
Note that some compilers lie about features they
support; i.e., __has_x(y)
will return
true, but if you try to use the feature an error will
occur. You should report these to the compiler developers
as they are discovered, but here is an incomplete list of
known problems:
If you encounter additional examples, please let us know so we can add them to the list.
To make it easier to check for features which are claimed
to be supported by a feature checking macro or a version
of GCC (or GNUC), Hedley also
provides HEDLEY_GCC/GNUC_HAS_*(x,major,minor,patch)
macros. These macros will use the __has_*()
macros if they exist, and if not will fall back
on
HEDLEY_GNUC_VERSION_CHECK(major,minor,revision)
/
HEDLEY_GCC_VERSION_CHECK(major,minor,revision)
:
#if HEDLEY_GNUC_HAS_ATTRIBUTE(noinline,4,0,0) __attribute__((__noinline__)) #endif
HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,revision)
HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(cpp_attribute,major,minor,revision)
HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,revision)
HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,revision)
HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(declspec_attribute,major,minor,revision)
HEDLEY_GNUC_HAS_WARNING(warning,major,minor,revision)
HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,revision)
HEDLEY_GCC_HAS_CPP_ATTRIBUTE(cpp_attribute,major,minor,revision)
HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,revision)
HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,revision)
HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(declspec_attribute,major,minor,revision)
HEDLEY_GCC_HAS_WARNING(warning,major,minor,revision)