Static Analysis

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.

Optimizations

Tell the compiler what you're doing (or what you want it to do) so compiled code is faster.

Manage Public APIs

Macros which help convey versioning information, when symbols are are added and deprecated, and symbol visibility.

C/C++ Compatibility

Macros to help make code useable from both C and C++.

Miscellaneous

Assorted macros which are useful, but don't really fit anywhere else.

Platform Detection

Macros Hedley uses to detect the platform.

Static Analysis

These macros are primarily intended to improve diagnostics (warnings and errors).

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()

Example
void print_array(int x, int y, char* elems[HEDLEY_ARRAY_PARAM(x * y)]);
Compiler Support
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.

Example
HEDLEY_WARN_UNUSED_RESULT
bool do_something(void);
Compiler Support
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.

position
Argument index, starting from 0 and counting right-to-left, of the sentinel.
Example
HEDLEY_SENTINEL(0)
void add_children(Context* ctx, ...);
Compiler Support
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.

Example
HEDLEY_NO_RETURN
void log_fatal(const char* message);
Compiler Support
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.

Example
switch (foo) {
	case FOO:
		handle_foo();
		HEDLEY_FALL_THROUGH;
	case BAR:
		handle_bar();
		break;
}
Compiler Support
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.

Example
HEDLEY_RETURNS_NON_NULL
void* foo(void);
Compiler Support
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).

Example
switch (foo) {
	case BAR:
		do_something();
		break;
	case BAZ:
		do_something_else();
		break;
	default:
		HEDLEY_UNREACHABLE();
		break;
}
Compiler Support
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.

Example
static int handle_code(enum Foo code) {
  switch (code) {
  case FOO_BAR:
  case FOO_BAZ:
  case FOO_QUX:
    return 0;
  }

  HEDLEY_UNREACHABLE_RETURN(0);
}
Compiler Support
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.

expr
Expression which is required to evaluate to true.
Example
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).

...
Variadic list of indexes (starting from 1, left-to-right) of parameters which must never be NULL.
Example
HEDLEY_NON_NULL(1,3)
void do_something(Context* ctx_cant_be_null, Foo* maybe_null, Bar* cant_be_null);
Compiler Support
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.

string_idx
Index (starts from 1, left-to-right) of the format string parameter.
first_to_check
Index of the first user-supplied parameter to check.
Example
HEDLEY_PRINTF_FORMAT(2,3)
void print_warning(Context* ctx, const char* fmt, ...);
Compiler Support
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.

expr
Expression to check.
Example
int foo(int a, int b)
  HEDLEY_REQUIRE(a < b);
Compiler Support
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.

expr
Expression to check.
msg
Message to display if the precondition fails.
Example
int foo(int a, int b)
  HEDLEY_REQUIRE(a < b, "a must be less than b");
Compiler Support
Platform Version Implementation
clang __has_attribute(diagnose_if) __attribute__((__diagnose_if__(expr, msg, "error")))

HEDLEY_FLAGS

Annotate an enumeration as containing bit flags.

Example
enum Foo {
	FOO_BAR = 1 << 0,
	FOO_BAZ = 1 << 1,
	FOO_QUX = 1 << 2
} HEDLEY_FLAGS;
							
Compiler Support
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.

T
Type to cast to.
expr
Expression to cast.
Example
const enum Foo foo = HEDLEY_FLAGS_CAST(enum Foo, FOO_BAR | FOO_BAZ);

Optimizations

Macros which are intended mostly to provide hints for optimizing compilers.

HEDLEY_LIKELY(expr)

Marks an expression as likely to evaluate to true (non-zero).

expr
Expression which is likely to evaluate true.
Example
if(HEDLEY_LIKELY(foo != NULL)) {
	do_something_with_foo(foo);
	return true;
} else {
	return false;
}
Compiler Support
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).

expr
Expression which is likely to evaluate false.
Example
Context* ctx = malloc(sizeof(Context));
if(HEDLEY_UNLIKELY(ctx == NULL))
	return ENOMEM;

ctx->foo = bar;
Compiler Support
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.

long expr
Expression for which to predict the value.
long expected
Value to which the expression is predicted to evaluate to.
double probability
Probability of the expression evaluating to the expected value.
Example
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.

expr
Expression for which to predict the value.
double probability
Probability of the expression evaluating to TRUE.
Example
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.

expr
Expression for which to predict the value.
double probability
Probability of the expression evaluating to FALSE.
Example
if (HEDLEY_PREDICT_FALSE(foo, 0.67)) {
  do_things();
}
              

This macro is similar to HEDLEY_UNLIKELY, but with a stated probability.

Example
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.

expr
Unpredictable expression.
Example
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.

Example
HEDLEY_MALLOC
uint8_t* create_buffer(void);
Compiler Support
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.

Example
HEDLEY_PURE
bool multiply(int* product, int a, int b);
Compiler Support
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.

Example
HEDLEY_CONST
int multiply(int a, int b);
Compiler Support
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.

Example
void do_something(int* HEDLEY_RESTRICT a, int* HEDLEY_RESTRICT b);
Compiler Support
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.

Example
HEDLEY_INLINE
void do_something_quickly(void);
Compiler Support
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.

Example
HEDLEY_ALWAYS_INLINE
void do_something_quickly(void);
Compiler Support
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.

Example
HEDLEY_NEVER_INLINE
void do_something(void);
Compiler Support
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.

Example
HEDLEY_NO_THROW
void do_something(void);
Compiler Support
__declspec(nothrow)
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+

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.

Example
void foo(HEDLEY_NO_ESCAPE Bar* baz);
Compiler Support
Platform Version Implementation
C
clang __has_attribute(noesecape) (clang 6.0+) __attribute__((__noescape__))

Manage Public APIs

Macros which are used to help manage APIs.

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).

major
Major version number.
minor
Minor version number.
revision
Revision number.
Example
HEDLEY_VERSION_ENCODE(1,2,3)
Compiler Support
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.

version
Encoded version number.
Compiler Support
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.

version
Encoded version number.
Compiler Support
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.

version
Encoded version number.
Compiler Support
Platform Version Implementation
C ((version) % 1000)

HEDLEY_DEPRECATED(since)

The symbol is deprecated and should not be used in new code.

since
First version in which this symbol was deprecated.
Example
HEDLEY_DEPRECATED(4.2)
void do_something(void);
Compiler Support
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.

since
First version in which this symbol was deprecated.
replacement
Name of the replacement.
Example
HEDLEY_DEPRECATED_FOR(4.2, do_something_better)
void do_something(void);
Compiler Support
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.

available_since
First version in which this symbol is available.
Example
HEDLEY_UNAVAILABLE(4.2)
void do_something(void);
Compiler Support
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.

Example
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.

C/C++ Compatibility

HEDLEY_BEGIN_C_DECLS

Tell a C++ compiler to begin use C linkage for the following symbols.

Example
HEDLEY_BEGIN_C_DECLS

void
do_something(void);

void
do_something_else(void);

HEDLEY_END_C_DECLS
Compiler Support
Platform Version Implementation
C
C++ extern "C" {

HEDLEY_END_C_DECLS

Tell a C++ compiler to stop using C linkage.

Example
HEDLEY_END_C_DECLS
void
do_something(void);
Compiler Support
Platform Version Implementation
C
C++ }

HEDLEY_C_DECL

Tell a C++ compiler to use C linkage for the symbol.

Example
HEDLEY_C_DECL
void
do_something(void);
Compiler Support
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).

Example
const char* foo = "Hello, world!";
char* bar = HEDLEY_CONST_CAST(char*, foo);
Compiler Support
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).

Example
uint8_t foo[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint64_t bar = *HEDLEY_REINTERPRET_CAST(uint64_t*, foo);
Compiler Support
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.

Example
int foo = 1729;
unsigned int bar = HEDLEY_STATIC_CAST(unsigned int, foo);
Compiler Support
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.

Example
enum Foo foo = HEDLEY_CPP_CAST(enum Foo, FOO_BAR | FOO_BAZ);
Compiler Support
Platform Version Implementation
C
C++ static_cast<T>(expr)

Miscellaneous

HEDLEY_STATIC_ASSERT(expr)

Perform a compile-time assertion; note that the it must be possible to evaluate expr at compile-time.

expr
An expression the compiler can evaluate at compile-time.
message
Error message to be emitted if the assertion fails.
Example
HEDLEY_STATIC_ASSERT(sizeof(int) >= 4, "int must be at least 32-bits");
Compiler Support
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.

Example
HEDLEY_DEPRECATED void foo(void);

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
static void bar(void) {
	foo();
}
HEDLEY_DIAGNOSTIC_POP
Compiler Support
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.

Example
HEDLEY_DEPRECATED
void foo(void);

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
static void bar(void) {
	foo();
}
HEDLEY_DIAGNOSTIC_POP
Compiler Support
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.

Example
HEDLEY_DEPRECATED void foo(void);

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
static void bar(void) {
	foo();
}
HEDLEY_DIAGNOSTIC_POP
Compiler Support
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.

Example
HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
#pragma foo bar
hEDLEY_DIAGNOSTIC_POP
Compiler Support
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.

Example
const char* foo = "Hello, world!";
HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
char* bar = foo;
hEDLEY_DIAGNOSTIC_POP
Compiler Support
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.

Example
HEDLEY_PRAGMA(omp simd)
Compiler Support
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.

Example
#define BAR bar

const char*
foo_bar(void) {
  return HEDLEY_STRINGIFY(BAR);
}

HEDLEY_CONCAT(a,b)

Concatenate two values.

Example
#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.

Example
#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).

Example
char foo[HEDLEY_REQUIRE_CONSTEXPR()];

HEDLEY_CONSTEXPR(expr)

The C++ constexpr qualifier if it is supported.

Example
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.

Example
foo(HEDLEY_NULL);

HEDLEY_MESSAGE(msg)

Emit a non-fatal compile-time informational message.

Example
HEDLEY_MESSAGE("Message goes here")
Compiler Support
GCC 4.4+ _Pragma("message msg")
ICC 16+ _Pragma("message msg")
Clang HEDLEY_DIAGNOSTIC_PUSH \
_Pragma("clang diagnostic ignored "-Wunknown-pragmas\"") \
_Pragma("message msg") \
HEDLEY_DIAGNOSTIC_POP
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.

Example
#if !defined(HAVE_PTHREADS) && !defined(_WIN32)
  HEDLEY_WARNING("No mutex implementation found; code will not be thread-safe.")
#endif
Compiler Support
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)

Platform Detection

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:

  1. Identification
  2. Version checking
  3. Feature testing
  4. Feature or version testing

Compiler identification

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__.

Example
#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

Compiler version checking macros

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:

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)

Compiler feature testing macros

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)
Example
#if HEDLEY_HAS_ATTRIBUTE(noinline)
  __attribute__((__noinline__))
#endif

Many clang-based compilers implement these macros, including:

  • Apple
  • ARM v6+
  • IBM XL C/C++ 13+
  • Clang/C2
  • Emscripten

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:

Compiler Lie
Emscripten HEDLEY_HAS_BUILTIN(__builtin_bitreverse8/16/64)
IBM XL C/C++ HEDLEY_HAS_BUILTIN(__builtin_bitreverse8/16/32/64)
IBM XL C/C++ HEDLEY_HAS_BUILTIN(__builtin_add*/sub*)
IBM XL C/C++ HEDLEY_HAS_ATTRIBUTE(optnone)

If you encounter additional examples, please let us know so we can add them to the list.

Compiler feature or version testing macros

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):

Example
#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)