| /* |
| * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) |
| * |
| * SPDX-License-Identifier: BSD-2-Clause |
| */ |
| |
| #pragma once |
| |
| #include <utils/attribute.h> |
| |
| #if (defined(__clang__) && __has_feature(c_generic_selections)) || \ |
| (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && __STDC_VERSION__ >= 201112L) |
| |
| /* On a fully-compliant C11 compiler, we provide a generic mechanism for printing a variable. |
| * |
| * Example usage: |
| * |
| * int i = 42; |
| * printf(FORMAT_STRING(i), i); |
| * |
| * Some known gotchas: |
| * - Character literals are ints, so you will need to cast them to get sensible results: |
| * FORMAT_STRING((char)'a') |
| * - String literals are character arrays, so you will need to also cast them: |
| * FORMAT_STRING((char*)"hello world") |
| */ |
| |
| #define FORMAT_STRING(x) _Generic((x), \ |
| char: "%c", \ |
| signed char: "%hhd", \ |
| unsigned char: "%hhu", \ |
| short: "%hd", \ |
| unsigned short: "%hu", \ |
| int: "%d", \ |
| unsigned int: "%u", \ |
| long: "%ld", \ |
| unsigned long: "%lu", \ |
| long long: "%lld", \ |
| unsigned long long: "%llu", \ |
| double: "%f", \ |
| long double: "%Lf", \ |
| float: "%f", \ |
| char*: "%s", \ |
| void*: "%p", \ |
| \ |
| /* The remaining cases are not necessary on GCC, where lvalue conversion is performed, */ \ |
| /* but are needed for Clang, which does not do this conversion. */ \ |
| \ |
| const char: "%c", \ |
| const signed char: "%hhd", \ |
| const unsigned char: "%hhu", \ |
| const short: "%hd", \ |
| const unsigned short: "%hu", \ |
| const int: "%d", \ |
| const unsigned int: "%u", \ |
| const long: "%ld", \ |
| const unsigned long: "%lu", \ |
| const long long: "%lld", \ |
| const unsigned long long: "%llu", \ |
| const double: "%f", \ |
| const long double: "%Lf", \ |
| const float: "%f", \ |
| const char*: "%s", \ |
| const void*: "%p", \ |
| volatile char: "%c", \ |
| volatile signed char: "%hhd", \ |
| volatile unsigned char: "%hhu", \ |
| volatile short: "%hd", \ |
| volatile unsigned short: "%hu", \ |
| volatile int: "%d", \ |
| volatile unsigned int: "%u", \ |
| volatile long: "%ld", \ |
| volatile unsigned long: "%lu", \ |
| volatile long long: "%lld", \ |
| volatile unsigned long long: "%llu", \ |
| volatile double: "%f", \ |
| volatile long double: "%Lf", \ |
| volatile float: "%f", \ |
| volatile char*: "%s", \ |
| volatile void*: "%p" \ |
| \ |
| /* We assume that no one needs to print a const- *and* volatile-qualified variable. */ \ |
| ) |
| |
| #else |
| |
| /* In an unsupported compiler configuration, trigger a compile-time error if the user has |
| * attempted to use FORMAT_STRING. |
| */ |
| |
| extern const char *FORMAT_STRING(void *dummy, ...) |
| ERROR("FORMAT_STRING requires full C11 compiler support"); |
| |
| #endif |