blob: 653891785f0cfb9ead6856e4fed78ce472966153 [file] [log] [blame] [edit]
/*
* 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